WIP: #65 isClubRep fix #93
|
@ -5,6 +5,7 @@ from zope import component
|
|||
from .utils import authz_restrict_to_staff, authz_restrict_to_syscom, \
|
||||
user_is_in_group, requires_authentication_no_realm, requires_admin_creds, \
|
||||
create_streaming_response, development_only, is_truthy
|
||||
from .model.utils import should_be_club_rep
|
||||
from ceo_common.errors import BadRequest, UserAlreadySubscribedError, UserNotSubscribedError
|
||||
from ceo_common.interfaces import ILDAPService, IConfig, IMailService
|
||||
from ceo_common.logger_factory import logger_factory
|
||||
|
@ -194,3 +195,28 @@ def remind_users_of_expiration():
|
|||
mail_srv.send_membership_renewal_reminder(member)
|
||||
|
||||
return jsonify([member.uid for member in members])
|
||||
|
||||
|
||||
@bp.route('/updateisclubrep', methods=['POST'])
|
||||
@authz_restrict_to_syscom
|
||||
def update_is_club_rep():
|
||||
dry_run = is_truthy(request.args.get('dry_run', 'false'))
|
||||
ldap_srv = component.getUtility(ILDAPService)
|
||||
members = ldap_srv.get_members()
|
||||
|
||||
modified_uids = []
|
||||
for member in members:
|
||||
current_club_rep_status = member.is_club_rep
|
||||
new_club_rep_status = should_be_club_rep(member.non_member_terms)
|
||||
if current_club_rep_status == new_club_rep_status:
|
||||
continue
|
||||
|
||||
modified_uids.append(member.uid)
|
||||
if not dry_run:
|
||||
member.set_club_rep(new_club_rep_status)
|
||||
if new_club_rep_status:
|
||||
logger.info(f"Updated {member.uid} to be club rep")
|
||||
else:
|
||||
logger.info(f"Updated {member.uid} to be non club rep")
|
||||
|
||||
return jsonify(modified_uids)
|
||||
|
|
|
@ -359,6 +359,27 @@ class LDAPService:
|
|||
|
||||
return users_to_change
|
||||
|
||||
def _get_member_uids(self, conn: ldap3.Connection) -> List[str]:
|
||||
conn.extend.standard.paged_search(self.ldap_users_base,
|
||||
'(objectClass=member)',
|
||||
attributes=['uid'],
|
||||
paged_size=50,
|
||||
generator=False)
|
||||
return [entry.uid.value for entry in conn.entries]
|
||||
|
||||
def get_members(self) -> List[IUser]:
|
||||
batch_size = 100
|
||||
conn = self._get_ldap_conn()
|
||||
member_uids = self._get_member_uids(conn)
|
||||
members = []
|
||||
for i in range(0, len(member_uids), batch_size):
|
||||
member_uids_slice = member_uids[i:i + batch_size]
|
||||
filter = '(|' + ''.join([f'(uid={uid})' for uid in member_uids_slice]) + ')'
|
||||
conn.search(self.ldap_users_base, filter, attributes=ldap3.ALL_ATTRIBUTES)
|
||||
for entry in conn.entries:
|
||||
members.append(User.deserialize_from_ldap(entry))
|
||||
return members
|
||||
|
||||
def _get_club_uids(self, conn: ldap3.Connection) -> List[str]:
|
||||
conn.extend.standard.paged_search(self.ldap_users_base,
|
||||
'(objectClass=club)',
|
||||
|
|
|
@ -64,7 +64,7 @@ class User:
|
|||
# not a real user
|
||||
is_club_rep = False
|
||||
else:
|
||||
is_club_rep = should_be_club_rep(terms, non_member_terms)
|
||||
is_club_rep = should_be_club_rep(non_member_terms)
|
||||
self.is_club_rep = is_club_rep
|
||||
if is_member_or_club_rep is None:
|
||||
is_member_or_club_rep = terms is not None or non_member_terms is not None
|
||||
|
@ -230,3 +230,8 @@ class User:
|
|||
else:
|
||||
entry.shadowExpire.remove()
|
||||
self.shadowExpire = None
|
||||
|
||||
def set_club_rep(self, is_club_rep: bool):
|
||||
with self.ldap_srv.entry_ctx_for_user(self) as entry:
|
||||
entry.isClubRep = is_club_rep
|
||||
self.is_club_rep = is_club_rep
|
||||
|
|
|
@ -34,17 +34,15 @@ def dn_to_uid(dn: str) -> str:
|
|||
return dn.split(',', 1)[0].split('=')[1]
|
||||
|
||||
|
||||
def should_be_club_rep(terms: Union[None, List[str]],
|
||||
non_member_terms: Union[None, List[str]]) -> bool:
|
||||
"""Returns True iff a user's most recent term was a non-member term."""
|
||||
def should_be_club_rep(non_member_terms: Union[None, List[str]]) -> bool:
|
||||
"""Returns True iff a user should be a club rep in the current term."""
|
||||
if not non_member_terms:
|
||||
# no non-member terms => was only ever a member
|
||||
return False
|
||||
if not terms:
|
||||
# no member terms => was only ever a club rep
|
||||
return True
|
||||
# decide using the most recent term (member or non-member)
|
||||
return max(map(Term, non_member_terms)) > max(map(Term, terms))
|
||||
|
||||
current_term = Term.current()
|
||||
most_recent_non_member_term = max(map(Term, non_member_terms))
|
||||
return most_recent_non_member_term == current_term
|
||||
|
||||
|
||||
def rate_limit(api_name: str, limit_secs: int):
|
||||
|
|
|
@ -26,7 +26,7 @@ conn.search(LDAP_MEMBERS_BASE, '(objectClass=member)',
|
|||
attributes=['uid', 'isClubRep', 'term', 'nonMemberTerm'])
|
||||
total_records_updated = 0
|
||||
for entry in conn.entries:
|
||||
if not should_be_club_rep(entry.term.values, entry.nonMemberTerm.values):
|
||||
if not should_be_club_rep(entry.nonMemberTerm.values):
|
||||
continue
|
||||
if entry.isClubRep.value:
|
||||
continue
|
||||
|
|
Loading…
Reference in New Issue