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

Add public statistics page #224

Merged
merged 4 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions module/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,27 @@ def all_clothes(pid: str) -> Generator[dict[str, Any], None, None]:
'''
yield from FormDB().find({'case': 'clothes', 'pid': pid})

@staticmethod
def get_clothes_statistics(pid: str) -> dict[str, int]:
''' Get clothes statistics by given pid '''
result = {
'XS': 0,
'S': 0,
'M': 0,
'L': 0,
'XL': 0,
'2XL': 0,
'3XL': 0,
'4XL': 0,
'5XL': 0,
'6XL': 0,
}

for form in Form.all_clothes(pid=pid):
result[form['data']['clothes']] += 1

return result

@staticmethod
def update_parking_card(pid: str, uid: str, data: dict[str, Any]) -> dict[str, Any]:
''' Update parking card
Expand Down Expand Up @@ -429,6 +450,19 @@ def get(pid: str) -> Generator[dict[str, Any], None, None]:
'''
yield from FormDB().find({'case': 'accommodation', 'pid': pid, 'data.key': {'$ne': 'no'}})

@staticmethod
def get_statistics(pid: str) -> dict[str, int]:
''' Get accommodation statistics by given pid '''
result = {
'yes': 0,
'yes-longtraffic': 0,
}

for form in FormAccommodation.get(pid=pid):
result[form['data']['key']] += 1

return result

@staticmethod
def update_room(pid: str, uid: str, room: str, change_key: bool = True) -> dict[str, Any]:
''' Update room no
Expand Down
22 changes: 21 additions & 1 deletion module/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from models.oauth_db import OAuthDB
from models.users_db import PolicySignedDB, TobeVolunteerDB, UsersDB
from module.dietary_habit import DietaryHabitItemsValue
from module.dietary_habit import DietaryHabitItemsName, DietaryHabitItemsValue
from module.mattermost_bot import MattermostTools
from module.skill import TobeVolunteerStruct
from structs.users import PolicyType
Expand Down Expand Up @@ -425,6 +425,26 @@ def marshal_dietary_habit(user_infos: dict[str, Any]) -> Generator[dict[str, Any

yield data

@staticmethod
def get_dietary_habit_statistics(uids: list[str]) -> dict[str, int]:
''' Get dietary habit statistics by given uids '''
result: dict[str, int] = { }

for item in DietaryHabitItemsName:
result[item.value] = 0

user_infos = User.get_info(uids=uids)
for user_info in user_infos.values():
if "profile_real" not in user_info or \
"dietary_habit" not in user_info["profile_real"]:
continue

for habit in user_info["profile_real"]["dietary_habit"]:
habit_enum_name = DietaryHabitItemsValue(habit).name
result[DietaryHabitItemsName[habit_enum_name].value] += 1

return result


class TobeVolunteer:
''' TobeVolunteer '''
Expand Down
91 changes: 91 additions & 0 deletions templates/project_statistics.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{% extends "base.html" %}
{% block head_title %}{{project.name}} 統計資訊{% endblock %}
{% block body %}
<section class="section">
<div class="container">
<h1 class="title">
{{project.name}}
</h1>
<div class="content">
<p>{{project.desc}}</p>
{% if editable %}
<div class="buttons is-right">
<a class="button is-info is-light" href="/project/{{project._id}}/edit">
<span class="icon"><i class="far fa-edit"></i></span> <span>Edit</span>
</a>
</div>
{% endif %}
</div>
</div>
</section>
<section class="section">
<div class="container">
<div class="tabs">
<ul>
<li><a href="/project/{{project._id}}">組別列表</a></li>
<li class="is-active"><a>統計資訊</a></li>
</ul>
</div>
<div class="columns">
<div class="column">
<h4 class="title is-4">飲食習慣人數分布</h4>
<table class="table">
<thead>
<th>習慣</th>
<th>人數</th>
</thead>
<tbody>
{% for habit, count in habit_statistics.items() %}
<tr>
<td>{{ habit }}</td>
<td>{{ count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="column">
<h4 class="title is-4">衣服尺寸人數分布</h4>
<table class="table">
<thead>
<th>尺寸</th>
<th>人數</th>
</thead>
<tbody>
{% for clothes_size, count in clothes_statistics.items() %}
<tr>
<td>{{ clothes_size }}</td>
<td>{{ count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="column">
<h4 class="title is-4">住宿人數</h4>
<table class="table">
<thead>
<th>住宿選項</th>
<th>人數</th>
</thead>
<tbody>
{% for accmmodation_option, count in accommodation_statictics.items() %}
{% if accmmodation_option == 'yes' %}
<tr>
<td>需要住宿</td>
<td>{{ count }}</td>
</tr>
{% elif accmmodation_option == 'yes-longtraffic' %}
<tr>
<td>需要住宿,且通勤時間大於一小時</td>
<td>{{ count }}</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</section>
{% endblock %}
6 changes: 6 additions & 0 deletions templates/project_teams_index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ <h1 class="title">
</section>
<section class="section">
<div class="container">
<div class="tabs">
<ul>
<li class="is-active"><a>組別列表</a></li>
<li><a href="/project/{{project._id}}/statistics">統計資訊</a></li>
</ul>
</div>
<div class="content">
<p><span class="tag">總人數:{{total}}</span></p>
</div>
Expand Down
28 changes: 28 additions & 0 deletions view/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,34 @@ def team_page(pid: str) -> str | ResponseBase:
)


@VIEW_PROJECT.route('/<pid>/statistics', methods=('GET',))
def project_statictics(pid: str) -> str | ResponseBase:
''' Statistics page '''
project = Project.get(pid)
if not project:
return Response('no data', status=404)

editable = g.user['account']['_id'] in project.owners

all_users = set()
for team in Team.list_by_pid(pid=pid):
if team.chiefs:
all_users.update(team.chiefs)
if team.members:
all_users.update(team.members)

habit_statistics = User.get_dietary_habit_statistics(uids=list(all_users))
clothes_statistics = Form.get_clothes_statistics(pid=pid)
accommodation_statictics = FormAccommodation.get_statistics(pid=pid)

return render_template('./project_statistics.html',
project=project.dict(by_alias=True),
habit_statistics=habit_statistics,
clothes_statistics=clothes_statistics,
accommodation_statictics=accommodation_statictics,
editable=editable)


@VIEW_PROJECT.route('/<pid>/form_traffic_mapping', methods=('GET', 'POST'))
def project_form_traffic_mapping(pid: str) -> str | ResponseBase:
''' Project form traffic mapping '''
Expand Down