Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

432 account overview list details page #605

Merged
merged 37 commits into from Apr 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
cc91a96
Add user.last_seen to CLI command show account
nhoening Mar 9, 2023
6f878dd
Document health API
nhoening Mar 9, 2023
4318518
Start /accounts API: GET endpoints
nhoening Mar 9, 2023
aa80880
remove two debugging statements
nhoening Mar 9, 2023
4364b52
use utility function for headers, fix typo
nhoening Mar 13, 2023
f0988f2
support new-style Optional shorthand in Python > 3.10
nhoening Mar 13, 2023
56d4dea
Merge branch 'main' into 432-account-overview-list-details-page
nhoening Mar 13, 2023
f0e5a32
update the number of accounts, as PR 602 added two more
nhoening Mar 13, 2023
a765bc5
feat(CRUD): add R of accounts CRUD
Mar 15, 2023
cbf73ce
three textual corrections
nhoening Mar 15, 2023
869890b
get_accounts util function returns empty list if unknown role is pass…
nhoening Mar 15, 2023
a33f42f
feat(CRUD): updated accounts tests and added links to user pages
Mar 20, 2023
19d49f7
feat(CRUD): add accounts to navbar and get single account through api
Mar 21, 2023
2310160
feat(CRUD): review comments implemented
Mar 21, 2023
24d40dd
fix docstring in API /index
nhoening Mar 23, 2023
20f61f9
chore(changelog): API changelog added accounts endpoints
Mar 23, 2023
b37fc5b
chore(changelog): changelog added accounts endpoints and pages
Mar 23, 2023
0ab0aa6
chore(changelog): changelog added accounts endpoints and pages
Mar 23, 2023
b6b5820
Merge branch 'main' into 432-account-overview-list-details-page
GustaafL Mar 23, 2023
455c92a
chore(changelog): changelog added accounts endpoints and pages
Mar 23, 2023
5307d5a
chore(changelog): PR number corrected
GustaafL Mar 24, 2023
c8e33f2
Merge branch 'main' into 432-account-overview-list-details-page
GustaafL Mar 24, 2023
8509d10
feat(account): accountpage updated with asset and user info
Mar 28, 2023
d098f03
feat(accounts): Add user and asset counts to accounts page
Apr 4, 2023
58409f6
Add account role schema (#625)
Flix6x Apr 5, 2023
cb4d78d
test
Apr 6, 2023
bcd584f
feat(accounts): account role names added to the account pages
Apr 6, 2023
b768c1b
Merge branch 'main' into 432-account-overview-list-details-page
GustaafL Apr 6, 2023
8d152b5
refactor(users): review changes, updated changelog and typing
Apr 7, 2023
1b342fe
refactor(crud): review changes to html templates
Apr 13, 2023
10d4d9a
Remove redundant lines
Flix6x Apr 17, 2023
7413643
Fix type annotations
Flix6x Apr 17, 2023
e1f49e8
Fix button for including inactive users
Flix6x Apr 17, 2023
becb83d
Move button to the side
Flix6x Apr 17, 2023
711396a
Merge remote-tracking branch 'origin/main' into 432-account-overview-…
Flix6x Apr 17, 2023
557fbaf
Fix data sort on copy of users table
Flix6x Apr 17, 2023
09f2a52
Add missing decorators to fix redirects to the login page
Flix6x Apr 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions flexmeasures/ui/__init__.py
Expand Up @@ -37,11 +37,13 @@ def register_at(app: Flask):

from flexmeasures.ui.crud.assets import AssetCrudUI
from flexmeasures.ui.crud.users import UserCrudUI
from flexmeasures.ui.crud.accounts import AccountCrudUI
from flexmeasures.ui.views.sensors import SensorUI

AssetCrudUI.register(app)
UserCrudUI.register(app)
SensorUI.register(app)
AccountCrudUI.register(app)

import flexmeasures.ui.views # noqa: F401 this is necessary to load the views

Expand Down
56 changes: 56 additions & 0 deletions flexmeasures/ui/crud/accounts.py
@@ -0,0 +1,56 @@
from flask import url_for
from flask_classful import FlaskView
from flask_login import current_user
from flexmeasures.ui.crud.api_wrapper import InternalApi

from flexmeasures.auth.policy import ADMIN_READER_ROLE, ADMIN_ROLE
from flexmeasures.ui.utils.view_utils import render_flexmeasures_template


def get_accounts():
GustaafL marked this conversation as resolved.
Show resolved Hide resolved
"""/accounts"""
accounts = []
if current_user.has_role(ADMIN_ROLE) or current_user.has_role(ADMIN_READER_ROLE):
accounts_response = InternalApi().get(url_for("AccountAPI:index"))
accounts = accounts_response.json()
else:
accounts = [
{
"id": current_user.user_account.id,
Flix6x marked this conversation as resolved.
Show resolved Hide resolved
"name": current_user.account.name,
"account_roles": [
current_user.account.account_roles[i].id
for i in current_user.account.account_roles
],
}
]

return accounts


def get_account(account_id: str):
GustaafL marked this conversation as resolved.
Show resolved Hide resolved
account_response = InternalApi().get(url_for("AccountAPI:get", id=account_id))
account = account_response.json()

return account


class AccountCrudUI(FlaskView):
GustaafL marked this conversation as resolved.
Show resolved Hide resolved
route_base = "/accounts"
trailing_slash = False

def index(self):
"""/accounts"""
accounts = get_accounts()

return render_flexmeasures_template(
"crud/accounts.html",
accounts=accounts,
)

def get(self, account_id: str):
account = get_account(account_id)
return render_flexmeasures_template(
"crud/account.html",
account=account,
)
35 changes: 35 additions & 0 deletions flexmeasures/ui/templates/crud/account.html
@@ -0,0 +1,35 @@
{% extends "base.html" %}{% block title %} {% endblock %} {% block divs %} {% if account %}

<div class="container-fluid">
<div class="row">
<div class="col-sm-8">
<div class="account-data-table card">
<h2>Account overview</h2>
<small>Account: {{ account["name"] }}</small>
<table class="table table-striped table-responsive">
<tbody>
<tr>
<td>
ID
</td>
<td>
{{ account["account_id"] }}
Flix6x marked this conversation as resolved.
Show resolved Hide resolved
</td>
</tr>
<tr>
<td>
Account Roles
GustaafL marked this conversation as resolved.
Show resolved Hide resolved
</td>
<td>
{{ account["account_roles"] }}
Flix6x marked this conversation as resolved.
Show resolved Hide resolved
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-sm-2"></div>
</div>
</div>

{% endif %} {% endblock %}
38 changes: 38 additions & 0 deletions flexmeasures/ui/templates/crud/accounts.html
GustaafL marked this conversation as resolved.
Show resolved Hide resolved
@@ -0,0 +1,38 @@
{% extends "base.html" %} {% set active_page = "accounts" %} {% block title %} Account listing {% endblock %} {% block divs %}

<div class="container-fluid">
<div class="row">
<div class="col-sm-2"></div>
<div class="col-sm-8">
<table class="table table-striped table-responsive paginate">
GustaafL marked this conversation as resolved.
Show resolved Hide resolved
<thead>
<tr>
<th>Account</th>
<th>ID</th>
<th>Roles</th>

</tr>
</thead>
<tbody>
{% for account in accounts %}
<tr>
<td>
{{ account["name"] }}
</td>
<td>
{{ account["id"] }}
</td>
<td>
{{ account["account_roles"]|join(", ") }}
Flix6x marked this conversation as resolved.
Show resolved Hide resolved
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="col-sm-2"></div>
</div>
</div>

{% block paginate_tables_script %} {{ super() }} {% endblock %} {% endblock%}
71 changes: 71 additions & 0 deletions flexmeasures/ui/tests/test_account_crud.py
GustaafL marked this conversation as resolved.
Show resolved Hide resolved
@@ -0,0 +1,71 @@
from flask_login import current_user
from flask import url_for
from flexmeasures.ui.crud.api_wrapper import InternalApi
from flexmeasures.ui.crud.accounts import get_accounts, get_account
from flexmeasures.ui.tests.utils import mock_account_response


def test_account_list(client, as_admin, requests_mock):
requests_mock.get(
"http://localhost//api/v3_0/accounts",
status_code=200,
json=mock_account_response(multiple=True),
)
requests_mock.get(
"http://localhost//api/v3_0/accounts/1",
status_code=200,
json=mock_account_response(multiple=True),
)
account_index = InternalApi().get(url_for("AccountAPI:index"))

get_accounts_response = InternalApi().get(url_for("AccountAPI:get", id=1))
print(get_accounts_response)
assert account_index.status_code == 200
# assert 1==2
Flix6x marked this conversation as resolved.
Show resolved Hide resolved


def test_account(client, as_admin, requests_mock):
mock_account = mock_account_response(as_list=False)
requests_mock.get(
"http://localhost//api/v3_0/accounts/1",
status_code=200,
json=mock_account,
)

get_account_response = InternalApi().get(url_for("AccountAPI:get", id=1))
print(get_account_response.json())
print(current_user.account)
# assert 1 == 2


def test_get_accounts(client, as_admin, requests_mock):
requests_mock.get(
"http://localhost//api/v3_0/accounts",
status_code=200,
json=mock_account_response(multiple=True),
)
accounts = get_accounts()
print(accounts)
assert get_accounts() == [
{"id": 1, "name": "test_account", "account_roles": []},
{
"id": 2,
"name": "test_account",
Flix6x marked this conversation as resolved.
Show resolved Hide resolved
"account_roles": [],
"account_name": "test_account2",
},
]


def test_get_account(client, as_admin, requests_mock):
mock_account = mock_account_response(as_list=False)
requests_mock.get(
"http://localhost//api/v3_0/accounts/1",
status_code=200,
json=mock_account,
)
assert get_account(account_id="1") == {
"id": 1,
"name": "test_account",
"account_roles": [],
}
24 changes: 24 additions & 0 deletions flexmeasures/ui/tests/utils.py
Expand Up @@ -75,3 +75,27 @@ def mock_api_data_as_form_input(api_data: dict) -> dict:
form_input = copy.deepcopy(api_data)
form_input["account"] = api_data["account_id"]
return form_input


def mock_account_response(
account_id: int = 1,
account_name: str = "test_account",
account_roles: list = [],
as_list: bool = True,
multiple: bool = False,
) -> Union[dict, List[dict]]:
account = dict(
id=account_id,
name=account_name,
account_roles=account_roles,
)
if as_list:
account_list = [account]
if multiple:
user2 = copy.deepcopy(account)
Flix6x marked this conversation as resolved.
Show resolved Hide resolved
user2["id"] = 2
user2["account_name"] = "test_account2"
Flix6x marked this conversation as resolved.
Show resolved Hide resolved
user2["account_roles"] = []
account_list.append(user2)
return account_list
return account