diff --git a/chezbetty/__init__.py b/chezbetty/__init__.py index c2afeb1..18b7baf 100644 --- a/chezbetty/__init__.py +++ b/chezbetty/__init__.py @@ -190,6 +190,7 @@ def debug(request): config.add_route('admin_users_email_oneperson', '/admin/users/email/oneperson') config.add_route('admin_users_email_all', '/admin/users/email/all') config.add_route('admin_user', '/admin/user/{user_id}') + config.add_route('admin_user_details', '/admin/user/{user_id}/details') config.add_route('admin_user_search_json', '/admin/user/search/{search}/json') config.add_route('admin_user_balance_edit', '/admin/user/balance/edit') config.add_route('admin_user_balance_edit_submit', '/admin/user/balance/edit/submit') diff --git a/chezbetty/models/user.py b/chezbetty/models/user.py index c1d0b3b..a668c14 100644 --- a/chezbetty/models/user.py +++ b/chezbetty/models/user.py @@ -24,6 +24,19 @@ class LDAPLookup(object): BASE_DN = "ou=People,dc=umich,dc=edu" PASSWORD = None ATTRIBUTES = ["uid", "entityid", "displayName"] + # http://www.itcs.umich.edu/itcsdocs/r1463/attributes-for-ldap.html + DETAILS_ATTRIBUTES = [ + # Could be interesting but require extra perm's from ITS + #"umichInstRoles", + #"umichAlumStatus", + #"umichAAAcadProgram", + #"umichAATermStatus", + #"umichHR", + "notice", + "ou", + "umichDescription", + "umichTitle", + ] def __init__(self): self.__conn = None @@ -38,14 +51,14 @@ def __connect(self): ) - def __lookup(self, k, v): + def __do_lookup(self, k, v, attributes, full_dict=False): self.__connect() query = "(%s=%s)" % (k, v) try: self.__conn.search(self.BASE_DN, query, ldap3.SEARCH_SCOPE_WHOLE_SUBTREE, - attributes=self.ATTRIBUTES + attributes=attributes ) except: # sometimes our connections time out @@ -54,22 +67,41 @@ def __lookup(self, k, v): self.__conn.search(self.BASE_DN, query, ldap3.SEARCH_SCOPE_WHOLE_SUBTREE, - attributes=self.ATTRIBUTES + attributes=attributes ) if len(self.__conn.response) == 0: raise InvalidUserException() + + if full_dict: + return self.__conn.response[0]["attributes"] + return { "umid":self.__conn.response[0]["attributes"]["entityid"], "uniqname":self.__conn.response[0]["attributes"]["uid"][0], "name":self.__conn.response[0]["attributes"]["displayName"][0] } - def lookup_umid(self, umid): - return self.__lookup("entityid", umid) + def __lookup(self, k, v): + return self.__do_lookup(k, v, self.ATTRIBUTES) - def lookup_uniqname(self, uniqname): - return self.__lookup("uid", uniqname) + def __detail_lookup(self, k, v): + return self.__do_lookup(k, v, + self.ATTRIBUTES + self.DETAILS_ATTRIBUTES, + full_dict=True, + ) + + def lookup_umid(self, umid, details=False): + if details: + return self.__detail_lookup("entityid", umid) + else: + return self.__lookup("entityid", umid) + + def lookup_uniqname(self, uniqname, details=False): + if details: + return self.__detail_lookup("uid", uniqname) + else: + return self.__lookup("uid", uniqname) class User(account.Account): @@ -104,6 +136,9 @@ def __str__(self): def from_id(cls, id): return DBSession.query(cls).filter(cls.id == id).one() + def get_details(self): + return self.__ldap.lookup_uniqname(self.uniqname, details=True) + @classmethod def from_uniqname(cls, uniqname, local_only=False): u = DBSession.query(cls).filter(cls.uniqname == uniqname).first() diff --git a/chezbetty/static/js/chezbetty-common-onload.js b/chezbetty/static/js/chezbetty-common-onload.js index 90e2bfe..ebd5d1b 100644 --- a/chezbetty/static/js/chezbetty-common-onload.js +++ b/chezbetty/static/js/chezbetty-common-onload.js @@ -92,3 +92,9 @@ $(".rotate-divs").each(function () { }, parseInt(showing_div.attr('data-rotate-div-timeout'))); }); +$(".ajax-fill").each(function () { + console.log($(this)); + $(this).removeClass("ajax-fill"); + $(this).load($(this).attr("data-path")); +}); + diff --git a/chezbetty/templates/admin/macro_ajax.jinja2 b/chezbetty/templates/admin/macro_ajax.jinja2 new file mode 100644 index 0000000..98cf651 --- /dev/null +++ b/chezbetty/templates/admin/macro_ajax.jinja2 @@ -0,0 +1,7 @@ +{% macro fill(path, load_text=None) %} +
+ {% if load_text %} +

{{ load_text }}

+ {% endif %} +
+{% endmacro %} diff --git a/chezbetty/templates/admin/user.jinja2 b/chezbetty/templates/admin/user.jinja2 index a308792..d6a56e0 100644 --- a/chezbetty/templates/admin/user.jinja2 +++ b/chezbetty/templates/admin/user.jinja2 @@ -1,5 +1,6 @@ {% extends "base.jinja2" %} {% import "macro_graph.jinja2" as graph %} +{% import "macro_ajax.jinja2" as ajax %} {% set active_page = 'users' %} {% block title %}User{% endblock %} @@ -14,16 +15,23 @@

User Details

-
-
Name
{{ user.name }}
-
uniqname
{{ user.uniqname }}
-
UMID
{{ user.umid }}
-
Balance
{{ user.balance|format_currency|safe }}
-
Lifetime Discounts
{{ user.lifetime_discounts|format_currency|safe }}
-
Lifetime Fees
{{ user.lifetime_fees|format_currency|safe }}
-
Joined
{{ user.created_at|pretty_date|safe }}
-
Enabled
{{ button.onoff_switch("user", "enabled", user.id, user.enabled) }}
-
+
+
+
+
Name
{{ user.name }}
+
uniqname
{{ user.uniqname }}
+
UMID
{{ user.umid }}
+
Balance
{{ user.balance|format_currency|safe }}
+
Lifetime Discounts
{{ user.lifetime_discounts|format_currency|safe }}
+
Lifetime Fees
{{ user.lifetime_fees|format_currency|safe }}
+
Joined
{{ user.created_at|pretty_date|safe }}
+
Enabled
{{ button.onoff_switch("user", "enabled", user.id, user.enabled) }}
+
+
+
+ {{ ajax.fill("/admin/user/" + user.id|string + "/details", "Loading user details from LDAP...") }} +
+

{% if user.has_password == False %} {{ button.ajax_singleuse_button("Create and Email Password", "/admin/user/"~user.id~"/password/create") }} diff --git a/chezbetty/templates/admin/user_details.jinja2 b/chezbetty/templates/admin/user_details.jinja2 new file mode 100644 index 0000000..55da309 --- /dev/null +++ b/chezbetty/templates/admin/user_details.jinja2 @@ -0,0 +1,18 @@ +
+ {% if umichTitle %} +
Title
{{ umichTitle|join(", ") }}
+ {% endif %} + {% if ou %} +
Affiliations
{{ ou|join(", ") }}
+ {% endif %} + {# This is text that the user enters in the MCommunity Directory. They might + indicate the best way to contact them, who their administrative assistant is, + or any other sort of notice that they want. #} + {% if notice %} +
Notice
{{ notice }}
+ {% endif %} + {% if umichDescription %} +
About Me
{{ umichDescription }}
+ {% endif %} +
+ diff --git a/chezbetty/views_admin.py b/chezbetty/views_admin.py index 490bcaf..c7da05f 100644 --- a/chezbetty/views_admin.py +++ b/chezbetty/views_admin.py @@ -1984,6 +1984,17 @@ def admin_user(request): request.session.flash('Invalid user?', 'error') return HTTPFound(location=request.route_url('admin_index')) +@view_config(route_name='admin_user_details', + renderer='templates/admin/user_details.jinja2', + permission='admin') +def admin_user_details(request): + try: + user = User.from_id(request.matchdict['user_id']) + details = user.get_details() + return details + except Exception as e: + if request.debug: raise(e) + return '

Unknown error loading user detail.

' @view_config(route_name='admin_user_purchase_add', renderer='templates/admin/user_purchase_add.jinja2',