Skip to content

Commit

Permalink
Merge pull request #1483 from GSA/main
Browse files Browse the repository at this point in the history
4/26/2024 Production Deploy
  • Loading branch information
stvnrlly authored Apr 26, 2024
2 parents 0ace019 + 82279eb commit 226906f
Show file tree
Hide file tree
Showing 21 changed files with 430 additions and 237 deletions.
40 changes: 37 additions & 3 deletions app/main/views/register.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import base64
import json
import uuid
from datetime import datetime, timedelta

from flask import (
abort,
current_app,
flash,
redirect,
render_template,
request,
Expand All @@ -22,8 +25,9 @@
)
from app.main.views import sign_in
from app.main.views.verify import activate_user
from app.models.service import Service
from app.models.user import InvitedOrgUser, InvitedUser, User
from app.utils import hide_from_search_engines
from app.utils import hide_from_search_engines, hilite


@main.route("/register", methods=["GET", "POST"])
Expand Down Expand Up @@ -150,7 +154,26 @@ def set_up_your_profile():
if code and state:
access_token = sign_in._get_access_token(code, state)
user_email, user_uuid = sign_in._get_user_email_and_uuid(access_token)
redirect_url = request.args.get("next")

invite_data = state.encode("utf8")
invite_data = base64.b64decode(invite_data)
invite_data = json.loads(invite_data)
invited_service = Service.from_id(invite_data["service_id"])
invited_user_id = invite_data["invited_user_id"]
invited_user = InvitedUser.by_id(invited_user_id)

if user_email.lower() != invited_user.email_address.lower():
flash("You cannot accept an invite for another person.")
session.pop("invited_user_id", None)
abort(403)
else:
invited_user.accept_invite()
current_app.logger.debug(
hilite(
f"INVITED USER {invited_user.email_address} to service {invited_service.name}"
)
)
current_app.logger.debug(hilite("ACCEPTED INVITE"))

elif login_gov_error:
current_app.logger.error(f"login.gov error: {login_gov_error}")
Expand All @@ -174,5 +197,16 @@ def set_up_your_profile():
# activate the user
user = user_api_client.get_user_by_uuid_or_email(user_uuid, user_email)
activate_user(user["id"])
return redirect(url_for("main.show_accounts_or_dashboard", next=redirect_url))
usr = User.from_id(user["id"])
usr.add_to_service(
invited_service.id,
invite_data["permissions"],
invite_data["folder_permissions"],
invite_data["from_user_id"],
)
current_app.logger.debug(
hilite(f"Added user {usr.email_address} to service {invited_service.name}")
)
return redirect(url_for("main.show_accounts_or_dashboard"))

return render_template("views/set-up-your-profile.html", form=form)
1 change: 0 additions & 1 deletion app/main/views/sign_in.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,6 @@ def sign_in():
if url is not None:
url = url.replace("NONCE", token)
url = url.replace("STATE", token)

return render_template(
"views/signin.html",
form=form,
Expand Down
65 changes: 12 additions & 53 deletions app/main/views/verify.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
from notifications_utils.url_safe_token import check_token

from app import user_api_client
from app.extensions import redis_client
from app.main import main
from app.main.forms import TwoFactorForm
from app.models.user import InvitedOrgUser, InvitedUser, User
from app.models.user import User
from app.utils.login import redirect_to_sign_in


Expand Down Expand Up @@ -66,59 +65,19 @@ def verify_email(token):
def activate_user(user_id):
user = User.from_id(user_id)

# This is the login.gov path
login_gov_invite_data = redis_client.get(f"service-invite-{user.email_address}")
if login_gov_invite_data:
login_gov_invite_data = json.loads(login_gov_invite_data.decode("utf8"))

# This is the deprecated path for organization invites where we get id from session
session["current_session_id"] = user.current_session_id
organization_id = session.get("organization_id")

activated_user = user.activate()
activated_user.login()

# TODO when login.gov is mandatory, get rid of the if clause, it is deprecated.
invited_user = InvitedUser.from_session()
if invited_user:
service_id = _add_invited_user_to_service(invited_user)
return redirect(url_for("main.service_dashboard", service_id=service_id))
elif login_gov_invite_data:
service_id = login_gov_invite_data["service_id"]

user.add_to_service(
service_id,
login_gov_invite_data["permissions"],
login_gov_invite_data["folder_permissions"],
login_gov_invite_data["from_user_id"],
)
return redirect(url_for("main.service_dashboard", service_id=service_id))

# TODO when login.gov is mandatory, git rid of the if clause, it is deprecated.
invited_org_user = InvitedOrgUser.from_session()
if invited_org_user:
user_api_client.add_user_to_organization(invited_org_user.organization, user_id)
elif redis_client.get(f"organization-invite-{user.email_address}"):
organization_id = redis_client.raw_get(
f"organization-invite-{user.email_address}"
)
user_api_client.add_user_to_organization(
organization_id.decode("utf8"), user_id
)
# TODO add org invites back in the new way
# organization_id = redis_client.raw_get(
# f"organization-invite-{user.email_address}"
# )
# user_api_client.add_user_to_organization(
# organization_id.decode("utf8"), user_id
# )
organization_id = None

if organization_id:
return redirect(url_for("main.organization_dashboard", org_id=organization_id))
else:
return redirect(url_for("main.add_service", first="first"))

activated_user = user.activate()
activated_user.login()

def _add_invited_user_to_service(invitation):
user = User.from_id(session["user_id"])
service_id = invitation.service
user.add_to_service(
service_id,
invitation.permissions,
invitation.folder_permissions,
invitation.from_user.id,
)
return service_id
return redirect(url_for("main.add_service", first="first"))
13 changes: 13 additions & 0 deletions app/notify_client/service_api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,5 +497,18 @@ def get_notification_count(self, service_id):
def get_global_notification_count(self, service_id):
return self.get("/service/{}/notification-count".format(service_id))

def get_service_invite_data(self, redis_key):
"""
Retrieve service invite_data.
"""
return self.get("/service/invite/redis/{0}".format(redis_key))


service_api_client = ServiceAPIClient()


# TODO, if we try to call get_service_invite_data directly
# from verify, app complains the method is not defined
# If we wrap it like this, the app can find it.
def retrieve_service_invite_data(redis_key):
return service_api_client.get_service_invite_data(redis_key)
14 changes: 7 additions & 7 deletions app/templates/new/components/org_nav.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<nav class="navigation">
<ul>
<li><a class="usa-link{{ org_navigation.is_selected('dashboard') }}" href="{{ url_for('.organization_dashboard', org_id=current_org.id) }}">Usage</a></li>
<li><a class="usa-link{{ org_navigation.is_selected('team-members') }}" href="{{ url_for('.manage_org_users', org_id=current_org.id) }}">Team members</a></li>
<nav class="nav margin-bottom-4">
<ul class="usa-sidenav">
<li class="usa-sidenav__item"><a class="usa-link{{ org_navigation.is_selected('dashboard') }}" href="{{ url_for('.organization_dashboard', org_id=current_org.id) }}">Usage</a></li>
<li class="usa-sidenav__item"><a class="usa-link{{ org_navigation.is_selected('team-members') }}" href="{{ url_for('.manage_org_users', org_id=current_org.id) }}">Team members</a></li>
{% if current_user.platform_admin %}
<li><a class="usa-link{{ org_navigation.is_selected('settings') }}" href="{{ url_for('.organization_settings', org_id=current_org.id) }}">Settings</a></li>
<li><a class="usa-link{{ org_navigation.is_selected('trial-services') }}" href="{{ url_for('.organization_trial_mode_services', org_id=current_org.id) }}">Trial mode services</a></li>
<li><a class="usa-link{{ org_navigation.is_selected('billing') }}" href="{{ url_for('.organization_billing', org_id=current_org.id) }}">Billing</a></li>
<li class="usa-sidenav__item"><a class="usa-link{{ org_navigation.is_selected('settings') }}" href="{{ url_for('.organization_settings', org_id=current_org.id) }}">Settings</a></li>
<li class="usa-sidenav__item"><a class="usa-link{{ org_navigation.is_selected('trial-services') }}" href="{{ url_for('.organization_trial_mode_services', org_id=current_org.id) }}">Trial mode services</a></li>
<li class="usa-sidenav__item"><a class="usa-link{{ org_navigation.is_selected('billing') }}" href="{{ url_for('.organization_billing', org_id=current_org.id) }}">Billing</a></li>
{% endif %}
</ul>
</nav>
11 changes: 11 additions & 0 deletions app/templates/new/components/org_nav_breadcrumb.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<nav class="navigation-service usa-breadcrumb">
<ol class="usa-breadcrumb__list">
<li class="usa-breadcrumb__list-item">
<span class="usa-breadcrumb__label"><a href="{{ url_for('.organizations') }}" class="usa-link navigation-organization-link">Organizations:</a></span>
</li>
<li class="usa-breadcrumb__list-item">
<span class="usa-breadcrumb__label">{{ current_org.name }}</span>
</li>
<a href="{{ url_for('main.choose_account') }}" class="usa-link navigation-service">Switch service</a>
</ol>
</nav>
35 changes: 0 additions & 35 deletions app/templates/new/layouts/org_template.html

This file was deleted.

48 changes: 32 additions & 16 deletions app/templates/new/layouts/withnav_template.html
Original file line number Diff line number Diff line change
@@ -1,31 +1,47 @@
{% extends "/new/base.html" %}

{% block per_page_title %}
{% block service_page_title %}{% endblock %} – {{ current_service.name }}
{% block service_page_title %}{% endblock %}{% if current_service.name %} – {{ current_service.name }}{% endif %}
{% block org_page_title %}{% endblock %}{% if current_org.name %} – {{ current_org.name }}{% endif %}
{% endblock %}

{% block main %}
<div class="grid-container">
{% block serviceNavigation %}
{% include "new/components/service_navigation.html" %}
{% endblock %}
<!-- The withnav_template can be used to replace the settings_template. When it comes to setting_template and withnav_template, this service_navigation.html on line 10 is only used in withnav_template. In settings_template, it was not used. That is one out of the two differences between settings template and withnav template. Child templates that extends settings_template, include the block serviceNavigation but leave it empty because we don't need to call in service_navigation. Within the app, the only pages settings_template.html is used: manage-users.html, service-settings.html, and user-profile.html -->
<div class="grid-row margin-top-5">
{% if help %}
<div class="grid-col-3">
{% if current_org.name %}
{% else %}
<div class="grid-col-3">
{% include "new/components/service_navigation.html" %}
{% endif %}
{% endblock %}
{#
The withnav_template can serve as a replacement for both settings_template and org_template.html.

The file service_navigation.html is included only in withnav_template. It's not used in settings_template. That is one out of the two differences between settings template and withnav template. As a result, when other templates extend settings_template, they include the serviceNavigation block but keep it empty. The settings_template.html is specifically used for these pages in the app: manage-users.html, service-settings.html, and user-profile.html.

In addition, serviceNavigation should be empty on templates that previously extended org_template. For templates that previously extended org_template.html, there's an addition of the orgNavBreadcrumb block.
{% block orgNavBreadcrumb %}
{% include "/new/components/org_nav_breadcrumb.html" %}
{% endblock %}
#}
{% if current_org.name %}
{% block orgNavBreadcrumb %}{% include "/new/components/org_nav_breadcrumb.html" %}{% endblock %}
{% endif %}
<div class="grid-row margin-top-5">
<div class="tablet:grid-col-3">
{% block sideNavigation %}
{% include "/new/components/main_nav.html" %}
<!-- instead of "main_nav.html" include "settings_nav.html" for child templates that extends settings_template -->
{% if org_navigation_links %}
{% include "/new/components/org_nav.html" %}
{% else %}
{% include "/new/components/main_nav.html" %}
{% endif %}
{#
Include settings_nav.html for child templates that previously extended settings_template.

Include "org_nav.html" for child templates that previously extended org_template html
#}
{% endblock %}
</div>
{% if help %}
<div class="grid-col-8">
{% else %}
<div class="grid-col-9 padding-left-4">
{% endif %}
</div>
<div class="tablet:grid-col-9 tablet:padding-left-4">
{% block beforeContent %}
{% block backLink %}{% endblock %}
{% endblock %}
Expand Down
Loading

0 comments on commit 226906f

Please sign in to comment.