Skip to content

Commit

Permalink
update users list admin page
Browse files Browse the repository at this point in the history
no longer edit users on list of all users

can change role on user page

handle no longer in directory error
  • Loading branch information
bradjc committed Mar 20, 2016
1 parent 2886448 commit 9c3aa56
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 80 deletions.
2 changes: 1 addition & 1 deletion chezbetty/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ def debug(request):
config.add_route('admin_inventory_submit', '/admin/inventory/submit')

config.add_route('admin_users_edit', '/admin/users/edit')
config.add_route('admin_users_edit_submit', '/admin/users/edit/submit')
config.add_route('admin_users_email', '/admin/users/email')
config.add_route('admin_users_email_endofsemester', '/admin/users/email/endofsemester')
config.add_route('admin_users_email_deadbeats', '/admin/users/email/deadbeats')
Expand All @@ -202,6 +201,7 @@ def debug(request):
config.add_route('admin_user_password_create', '/admin/user/{user_id}/password/create')
config.add_route('admin_user_password_reset', '/admin/user/{user_id}/password/reset')
config.add_route('admin_user_archive', '/admin/user/{user_id}/archive')
config.add_route('admin_user_changerole', '/admin/user/{user_id}/changerole/{role}')

config.add_route('admin_pools', '/admin/pools')
config.add_route('admin_pool', '/admin/pool/{pool_id}')
Expand Down
20 changes: 20 additions & 0 deletions chezbetty/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,26 @@ def get_shame_users(cls):
.filter(cls.balance < -5)\
.order_by(cls.balance).all()

@classmethod
def get_normal_users(cls):
return DBSession.query(cls)\
.filter(cls.enabled)\
.filter(cls.archived == False)\
.order_by(cls.name).all()

@classmethod
def get_archived_users(cls):
return DBSession.query(cls)\
.filter(cls.enabled)\
.filter(cls.archived == True)\
.order_by(cls.name).all()

@classmethod
def get_disabled_users(cls):
return DBSession.query(cls)\
.filter(cls.enabled == False)\
.order_by(cls.name).all()

@classmethod
def get_users_total(cls):
return DBSession.query(func.sum(User.balance).label("total_balance"))\
Expand Down
10 changes: 10 additions & 0 deletions chezbetty/templates/admin/user.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<dt>Name</dt><dd>{{ user.name }}</dd>
<dt>uniqname</dt><dd><a href="https://mcommunity.umich.edu/#search:{{ user.uniqname }}">{{ user.uniqname }}</a></dd>
<dt>UMID</dt><dd>{{ user.umid }}</dd>
<dt>Role</dt><dd>{{ user.role }}</dd>
<dt>Balance</dt><dd>{{ user.balance|format_currency|safe }}</dd>
<dt>Lifetime Discounts</dt><dd>{{ user.lifetime_discounts|format_currency|safe }}</dd>
<dt>Lifetime Fees</dt><dd>{{ user.lifetime_fees|format_currency|safe }}</dd>
Expand All @@ -42,6 +43,15 @@
{% if not user.archived %}
{{ button.ajax_singleuse_button("Archive User", "/admin/user/"~user.id~"/archive") }}
{% endif %}
{% if not user.role == 'user' %}
{{ button.ajax_singleuse_button("Change role to User", "/admin/user/"~user.id~"/changerole/user") }}
{% endif %}
{% if not user.role == 'manager' %}
{{ button.ajax_singleuse_button("Change role to Manager", "/admin/user/"~user.id~"/changerole/manager") }}
{% endif %}
{% if not user.role == 'administrator' %}
{{ button.ajax_singleuse_button("Change role to Administrator", "/admin/user/"~user.id~"/changerole/administrator") }}
{% endif %}

</div>
</div>
Expand Down
115 changes: 76 additions & 39 deletions chezbetty/templates/admin/users_edit.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,81 @@
{% set sort=request.GET["sort"]|default(None) %}
{% set dir=request.GET["direction"]|default("asc") %}

<form role="form" action="/admin/users/edit/submit" method="post">

<table class="table sortable sticky">

<thead>
<tr class="user-list-header">
<th>&nbsp;</th>
<th {% if sort=="name" %}data-defaultsort="{{ dir }}"{% endif %}>Name</th>
<th {% if sort=="role" %}data-defaultsort="{{ dir }}"{% endif %} class="filterable-row">Role</th>
<th {% if sort=="balance" %}data-defaultsort="{{ dir }}"{% endif %} class="right">Balance</th>
<th {% if sort=="lastpurchase" %}data-defaultsort="{{ dir }}"{% endif %} class="right">Days Since Last Purchase</th>
<th {% if sort=="date" %}data-defaultsort="{{ dir }}"{% endif %}>Created Date</th>
</tr>
</thead>

<tbody>
{% for user in users %}
<tr id="user-{{ user.id }}" class="edit-user-row {% if user.enabled == False %} disabled-row {% endif %}">
<td><a href="/admin/user/{{ user.id }}"><span class="glyphicon glyphicon-user"></span></a></td>
<td data-value="{{ user.name }}"><input type="text" class="form-control" id="user-name-{{ user.id }}" name="user-name-{{ user.id }}" value="{{ user.name }}"></td>
<td data-value="{{ user.role }}">
<select class="form-control" id="user-role-{{ user.id }}" name="user-role-{{ user.id }}">
{% for role in roles %}
<option value="{{ role[0] }}" {% if role[0] == user.role %}selected="selected"{% endif %}>{{ role[1] }}</option>
{% endfor %}
</select>
</td>
<td class="right" data-value="{{ user.balance|round(2) }}">{{ user.balance|format_currency|safe }}</td>
<td data-value="{{ user.days_since_last_purchase }}" class="right">{{ user.days_since_last_purchase }}</td>
<td data-value="{{ user.created_at }}">{{ user.created_at|pretty_date|safe }}</td>
</tr>
{% endfor %}
</tbody>

</table>

<button type="submit" class="btn btn-success">Update users</button>

</form>

<table class="table sortable sticky">

<thead>
<tr class="user-list-header">
<th {% if sort=="name" %}data-defaultsort="{{ dir }}"{% endif %}>Name</th>
<th {% if sort=="role" %}data-defaultsort="{{ dir }}"{% endif %} class="filterable-row">Role</th>
<th {% if sort=="balance" %}data-defaultsort="{{ dir }}"{% endif %} class="right">Balance</th>
<th {% if sort=="lastpurchase" %}data-defaultsort="{{ dir }}"{% endif %} class="right">Days Since Last Purchase</th>
<th {% if sort=="date" %}data-defaultsort="{{ dir }}"{% endif %}>Created Date</th>
</tr>
</thead>

<tbody>
{% for user in normal_users %}
<tr id="user-{{ user.id }}" class="edit-user-row {% if user.enabled == False %} disabled-row {% endif %}">
<td data-value="{{ user.name }}">{{ user|make_link|safe }}</td>
<td data-value="{{ user.role }}">{{ roles[user.role] }}</td>
<td class="right" data-value="{{ user.balance|round(2) }}">{{ user.balance|format_currency|safe }}</td>
<td data-value="{{ user.days_since_last_purchase }}" class="right">{{ user.days_since_last_purchase }}</td>
<td data-value="{{ user.created_at }}">{{ user.created_at|pretty_date|safe }}</td>
</tr>
{% endfor %}
</tbody>

</table>

<h2>Archived Users</h2>
<table class="table sortable sticky">

<thead>
<tr class="user-list-header">
<th {% if sort=="name" %}data-defaultsort="{{ dir }}"{% endif %}>Name</th>
<th {% if sort=="role" %}data-defaultsort="{{ dir }}"{% endif %} class="filterable-row">Role</th>
<th {% if sort=="date" %}data-defaultsort="{{ dir }}"{% endif %}>Created Date</th>
</tr>
</thead>

<tbody>
{% for user in archived_users %}
<tr id="user-{{ user.id }}" class="edit-user-row {% if user.enabled == False %} disabled-row {% endif %}">
<td data-value="{{ user.name }}">{{ user|make_link|safe }}</td>
<td data-value="{{ user.role }}">{{ roles[user.role] }}</td>
<td data-value="{{ user.created_at }}">{{ user.created_at|pretty_date|safe }}</td>
</tr>
{% endfor %}
</tbody>

</table>

<h2>Disabled Users</h2>
<table class="table sortable sticky">

<thead>
<tr class="user-list-header">
<th {% if sort=="name" %}data-defaultsort="{{ dir }}"{% endif %}>Name</th>
<th {% if sort=="role" %}data-defaultsort="{{ dir }}"{% endif %} class="filterable-row">Role</th>
<th {% if sort=="balance" %}data-defaultsort="{{ dir }}"{% endif %} class="right">Balance</th>
<th {% if sort=="date" %}data-defaultsort="{{ dir }}"{% endif %}>Created Date</th>
</tr>
</thead>

<tbody>
{% for user in disabled_users %}
<tr id="user-{{ user.id }}" class="edit-user-row {% if user.enabled == False %} disabled-row {% endif %}">
<td data-value="{{ user.name }}">{{ user|make_link|safe }}</td>
<td data-value="{{ user.role }}">{{ roles[user.role] }}</td>
<td class="right" data-value="{{ user.balance|round(2) }}">{{ user.balance|format_currency|safe }}</td>
<td data-value="{{ user.created_at }}">{{ user.created_at|pretty_date|safe }}</td>
</tr>
{% endfor %}
</tbody>

</table>



{% endblock %}
78 changes: 38 additions & 40 deletions chezbetty/views_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from .models import *
from .models.model import *
from .models import user as __user
from .models.user import User
from .models.user import User, InvalidUserException
from .models.item import Item, ItemImage
from .models.box import Box
from .models.box_item import BoxItem
Expand Down Expand Up @@ -1922,43 +1922,17 @@ def admin_vendors_edit_submit(request):
renderer='templates/admin/users_edit.jinja2',
permission='admin')
def admin_users_edit(request):
enabled_users = DBSession.query(User).filter_by(enabled=True).order_by(User.name).all()
disabled_users = DBSession.query(User).filter_by(enabled=False).order_by(User.name).all()
users = enabled_users + disabled_users
roles = [('user', 'User'),
('serviceaccount', 'Service Account'),
('manager', 'Manager'),
('administrator', 'Administrator')]
return {'users': users, 'roles': roles}


@view_config(route_name='admin_users_edit_submit',
request_method='POST',
permission='admin')
def admin_users_edit_submit(request):
for key in request.POST:
user_id = int(key.split('-')[2])
field = key.split('-')[1]
val = request.POST[key].strip()

user = User.from_id(user_id)

if field == 'role' and user.role == 'user' and val != 'user':
# The user was previously just a user and now is being set to
# something else. Every other role type requires a password.
# Here, we set the password to the default (so the user can
# login) and the user can change it themselves.
user.password = request.registry.settings['chezbetty.default_password']

elif field == 'role' and user.role != 'user' and val == 'user':
# The user was something other than just a user and is being
# downgraded. The user no longer needs to be able to login
# so we reset the password.
user.password = ''

setattr(user, field, val)
request.session.flash('Users updated successfully.', 'success')
return HTTPFound(location=request.route_url('admin_users_edit'))
normal_users = User.get_normal_users()
archived_users = User.get_archived_users()
disabled_users = User.get_disabled_users()
roles = {'user': 'User',
'serviceaccount': 'Service Account',
'manager': 'Manager',
'administrator': 'Administrator'}
return {'normal_users': normal_users,
'archived_users': archived_users,
'disabled_users': disabled_users,
'roles': roles}


@view_config(route_name='admin_uniqname',
Expand Down Expand Up @@ -2003,6 +1977,8 @@ def admin_user_details(request):
user = User.from_id(request.matchdict['user_id'])
details = user.get_details()
return details
except InvalidUserException:
return {'notice': 'User no longer in the directory.'}
except Exception as e:
if request.debug: raise(e)
return {'notice': 'Unknown error loading user detail.'}
Expand Down Expand Up @@ -2119,15 +2095,14 @@ def admin_user_password_reset(request):
return {'status': 'error',
'msg': 'Error.'}

#

# Method for de-activating users who haven't used Betty in a while.
# This lets us handle users who don't go to north anymore or who
# have graduated.
#
# The balance they have when they are archived is recorded and then any
# balance or debt is moved to the chezbetty account. If the user ever does
# return, their old balance is restored.
#
@view_config(route_name='admin_user_archive',
renderer='json',
permission='admin')
Expand Down Expand Up @@ -2163,6 +2138,29 @@ def admin_user_archive(request):
return {'status': 'error',
'msg': 'Error.'}


# AJAX for changing user role
@view_config(route_name='admin_user_changerole',
renderer='json',
permission='admin')
def admin_user_changerole(request):
try:
user = User.from_id(int(request.matchdict['user_id']))
new_role = request.matchdict['role']

user.role = new_role

return {'status': 'success',
'msg': 'User role successfully changed to {}.'.format(new_role)}
except NoResultFound:
return {'status': 'error',
'msg': 'Could not find user.'}
except Exception as e:
if request.debug: raise(e)
return {'status': 'error',
'msg': 'Error.'}


@view_config(route_name='admin_users_email',
renderer='templates/admin/users_email.jinja2',
permission='admin')
Expand Down

0 comments on commit 9c3aa56

Please sign in to comment.