def create_inactive_user(memberid): Actor.get_personal_members().get(memberid=memberid) # Verify that the Actor exists try: # Check if the user object already exists first. existing_user = User.objects.get(memberid=memberid) # Note that we don't check if this user is inactive or not. # If they are, maybe someone double-clicked some link or something. # It doesn't matter, let this user pass as the created one. if existing_user.is_pending: # Well, we saw that they're not pending anymore since we checked the actor, so fix that and let them # pass. existing_user.is_pending = False existing_user.save() if existing_user.is_expired: # Oh, what happened here? Well, they're not expired anymore since the actor exists, so fix that and # let them pass. existing_user.is_expired = False existing_user.save() return existing_user except User.DoesNotExist: user = User(identifier=memberid, memberid=memberid, is_inactive=True) user.set_unusable_password() user.save() return user
def handle(self, *args, **options): members = User.objects.filter(memberid__isnull=False) pending_users = members.filter(is_pending=True) normal_users = members.filter(is_pending=False) # Check for pending users that recently got their Actor, and shouldn't be pending for u in pending_users.filter(is_expired=False): # This method automatically updates the user if not pending anymore u.verify_still_pending(ignore_cache=True) # Check for expired pending users that may have gotten their Actor or Enrollment object back # (doesn't make sense that this actually happens, but let's not make assumptions for Focus) for u in pending_users.filter(is_expired=True): if Actor.get_personal_members().filter(memberid=u.memberid).exists(): u.is_expired = False u.is_pending = False u.save() elif Enrollment.objects.filter(memberid=u.memberid).exists(): u.is_expired = False u.save() # Check for normal expired users that regained their Actor and shouldn't be expired anymore for u in normal_users.filter(is_expired=True): if Actor.get_personal_members().filter(memberid=u.memberid).exists(): u.is_expired = False u.save() # Check for normal users that have lost their Actor and should be expired for u in normal_users.filter(is_expired=False): if not Actor.get_personal_members().filter(memberid=u.memberid).exists(): u.is_expired = True u.save()
def confirm_membership(self): """Register that this member has confirmed their membership""" status = self.actor.get_membership_confirmation_status() if status.Bekreftet: return Actor.confirm_membership_by_token(status.Token)
def search(request): if not request.is_ajax() or request.method != 'POST': return redirect('admin.users.views.index') if len(request.POST['q']) < settings.ADMIN_USER_SEARCH_CHAR_LENGTH: raise PermissionDenied local_users = User.get_users().filter(memberid__isnull=True) for word in request.POST['q'].split(): local_users = local_users.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word)) local_users = local_users.order_by('first_name') actors = Actor.get_personal_members() for word in request.POST['q'].split(): actors = actors.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) | Q(memberid__icontains=word)) actors = actors.order_by('first_name') # Match expired users only on memberid expired_users = User.objects.all() for word in request.POST['q'].split(): expired_users = expired_users.filter(memberid__icontains=word) expired_users = [u for u in expired_users if not Actor.get_personal_members().filter(memberid=u.memberid).exists()] # Pending users pending_enrollment = Enrollment.get_active() for word in request.POST['q'].split(): pending_enrollment = pending_enrollment.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) | Q(memberid__icontains=word)) pending_enrollment = pending_enrollment.order_by('first_name') members = User.get_users().filter(memberid__in=[a.memberid for a in actors]) pending_users = User.get_users(include_pending=True).filter(memberid__in=[e.memberid for e in pending_enrollment]) actors_without_user = [a for a in actors if a.memberid not in list(members.values_list('memberid', flat=True))] users = list(local_users) + list(members) + list(pending_users) context = RequestContext(request, { 'users': users, 'actors_without_user': actors_without_user, 'expired_users': expired_users }) return HttpResponse(render_to_string('common/admin/users/user_results.html', context))
def check_memberid(request): if not request.user.can_modify_user_memberid(): raise PermissionDenied user_to_change = User.objects.get(id=request.POST['user']) memberid_is_equal = str(user_to_change.memberid) == request.POST['memberid'].strip() try: existing_user = User.objects.get(memberid=request.POST['memberid']) except (User.DoesNotExist, ValueError): existing_user = None try: actor = Actor.get_personal_members().get(memberid=request.POST['memberid']) except (Actor.DoesNotExist, ValueError): actor = None context = { 'user_to_change': user_to_change, 'existing_user': existing_user, 'actor': actor, 'memberid': request.POST['memberid'], 'memberid_is_equal': memberid_is_equal, } html = render_to_string('central/admin/users/check_memberid.html', context, request=request) return HttpResponse(json.dumps({ 'valid': actor is not None and not memberid_is_equal, 'html': html, }))
def attempt_login(request): matches = authenticate_users(request.POST['email'], request.POST['password']) if len(matches) == 1: # Exactly one match, cool, just authenticate the user user = authenticate(user=matches[0]) log_user_in(request, user) return matches, None elif len(matches) > 1: # Multiple matches, let the caller handle this return matches, None elif len(matches) == 0: # Incorrect credentials. Check if this is a user from the old userpage system old_member = authenticate_sherpa2_user(request.POST['email'], request.POST['password']) if old_member is not None: # Actually, it is! Let's try to import them. if User.get_users().filter(memberid=old_member.memberid, is_inactive=False).exists(): return matches, 'old_memberid_but_memberid_exists' # Check if a pending user exists. This shouldn't ever happen (a pending user is recently # enrolled, and an existing user will have been member for a long time). if User.objects.filter(memberid=old_member.memberid, is_pending=True).exists(): # Give the same error ("user exists, you need to use your new password") return matches, 'old_memberid_but_memberid_exists' # Verify that they exist in the membersystem (this turned out to be an incorrect assumption) if not Actor.get_personal_members().filter(memberid=old_member.memberid).exists(): # We're not quite sure why this can happen, so we'll just give them the invalid # credentials message - but this might be confusing for those who were able to log # in previously. return matches, 'invalid_credentials' # Create the new user try: # Check if the user's already created as inactive user = User.get_users().get(memberid=old_member.memberid, is_inactive=True) user.is_inactive = False user.set_password(request.POST['password']) user.save() except User.DoesNotExist: # New user user = User(identifier=old_member.memberid, memberid=old_member.memberid) user.set_password(request.POST['password']) user.save() # Update the email on this actor, in case it were to differ from the sherpa2 email user.update_personal_data({'email': request.POST['email']}) # Import any fjelltreffen-annonser from the old system import_fjelltreffen_annonser(user) authenticate(user=user) log_user_in(request, user) return [user], None else: # No luck, just provide the error message return matches, 'invalid_credentials'
def update_from_actors(self): t1 = time.time() if self.print_log: print(" update_from_actors()") self.main_stats['actor']['started'] = str(datetime.now()) actors = Actor.get_personal_members().order_by('id') if self.filter_from_date: actors = actors.filter(changed_date__gt=self.filter_from_date) bulk_count = 10000 p = Paginator(actors, bulk_count) self.main_stats['actor']['num_pages'] = p.num_pages self.main_stats['actor']['pages'] = {} if self.task_log: self.task_log.data = self.main_stats self.task_log.save() self.update(p, 'actor') self.main_stats['actor']['ended'] = str(datetime.now()) self.main_stats['actor']['duration'] = time.time() - t1 if self.task_log: self.task_log.data = self.main_stats self.task_log.save() if self.print_log: self.print_stats(self.main_stats['actor'], 4) print(" update_from_actors() done in %0.2fs" % self.main_stats['actor']['duration'])
def change_memberid(request): if not request.user.can_modify_user_memberid(): raise PermissionDenied # The Actor was already checked client-side, but verify here if not Actor.get_personal_members().filter(memberid=request.POST['new-memberid']).exists(): raise PermissionDenied old_user = User.objects.get(id=request.POST['old-user']) try: new_user = User.objects.get(memberid=request.POST['new-memberid']) # Ah, the new memberid already has a user - merge them, but keep the password # of the new user new_user.merge_with(old_user) # This will delete the old user resulting_user = new_user except User.DoesNotExist: # Allright, just update the memberid to the new one old_user.identifier = request.POST['new-memberid'] old_user.memberid = request.POST['new-memberid'] old_user.is_expired = False old_user.is_pending = False old_user.save() resulting_user = old_user if 'purge-busticket' in request.POST: ticket = resulting_user.norway_bus_ticket ticket.delete() return redirect('admin:users.show', resulting_user.id)
def __init__(self, memberid, actor=None): try: self.actor = actor if actor is not None else cache.get('actor.%s' % memberid) if self.actor is None: self.actor = Actor.get_personal_members().get(memberid=memberid) cache.set('actor.%s' % memberid, self.actor, settings.FOCUS_MEMBER_CACHE_PERIOD) except Actor.DoesNotExist: # The referenced memberid doesn't exist in the member system. This typically occurs when the member system # purges members who haven't been enrolled for 2 years or more. raise ExpiredMember("Actor with memberid '%s' does not exist" % memberid)
def get_children(self): from user.models import User children = cache.get('actor.%s.children' % self.actor.memberid) if children is None: actor_children = Actor.get_personal_members().filter(parent=self.actor.memberid).exclude(id=self.actor.id) children = [ User.get_or_create_inactive(memberid=actor_child.memberid) for actor_child in actor_children ] cache.set('actor.%s.children' % self.actor.memberid, children, settings.FOCUS_MEMBER_CACHE_PERIOD) return children
def users(request, forening_id): current_forening = Forening.objects.get(id=forening_id) if current_forening not in request.user.all_foreninger(): raise PermissionDenied forening_users = list(User.objects.filter(foreninger=current_forening)) forening_users_by_parent = [] parent_ids = [p.id for p in current_forening.get_parents_deep()] forening_users_by_parent_all = list(User.objects.filter(foreninger__in=parent_ids)) # Prefetch and cache the actors memberids = [u.memberid for u in (forening_users + forening_users_by_parent)] Actor.cache_all( Actor.get_personal_members().filter(memberid__in=memberids).prefetch_related('services') ) # Safe to iterate without having n+1 issues # Filter on admins forening_users_by_parent = [] for user in forening_users_by_parent_all: for forening in user.all_foreninger(): if forening == current_forening and forening.role == 'admin': forening_users_by_parent.append(user) forening_users = sorted(forening_users, key=lambda u: u.get_full_name()) forening_users_by_parent = sorted(forening_users_by_parent, key=lambda u: u.get_full_name()) context = { 'current_forening': current_forening, 'forening_users': forening_users, 'forening_users_by_parent': forening_users_by_parent, 'admin_user_search_char_length': settings.ADMIN_USER_SEARCH_CHAR_LENGTH, } return render(request, 'central/admin/foreninger/users.html', context)
def contact_person_search(request, forening_id): current_forening = Forening.objects.get(id=forening_id) if current_forening not in request.user.all_foreninger(): raise PermissionDenied MAX_HITS = 100 if len(request.POST['q']) < settings.ADMIN_USER_SEARCH_CHAR_LENGTH: raise PermissionDenied local_nonmember_users = User.get_users().filter(memberid__isnull=True) for word in request.POST['q'].split(): local_nonmember_users = local_nonmember_users.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) ) local_nonmember_users = local_nonmember_users.order_by('first_name') actors = Actor.get_personal_members() for word in request.POST['q'].split(): actors = actors.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) | Q(memberid__icontains=word) ) actors = actors.order_by('first_name') # Get (or create) the user objects for the first MAX_HITS actor-hits users = [ User.get_or_create_inactive(a.memberid) for a in actors[:MAX_HITS]] # Merge with non-members users = sorted( list(users) + list(local_nonmember_users), key=lambda u: u.get_full_name()) context = { 'current_forening': current_forening, 'users': users[:MAX_HITS], } return HttpResponse(json.dumps({ 'results': render_to_string( 'central/admin/foreninger/contact_person_search_results.html', context, request=request, ), 'max_hits_exceeded': len(users) > MAX_HITS or len(actors) > MAX_HITS }))
def verify_still_pending(self, ignore_cache=False): # If, for any reason, a non-member got is_pending set to True incorrectly, fix it if not self.is_member(): self.is_pending = False self.save() return False # Cache the check for an hour if not ignore_cache and cache.get('user.%s.checked_for_pending' % self.id) is not None: return True cache.set('user.%s.checked_for_pending' % self.id, True, 60 * 60) if Actor.get_personal_members().filter(memberid=self.memberid).exists(): self.is_pending = False self.save() return False else: return True
def cache_actors(memberids): # Run a search with several memberids towards Focus and recieve all # relevant actor data. Then cache the result. # This prevents multiple queries to Focus when for instance looping # through users to display their name # If we have more than 2100 parameters, MSSQL will cry, so split it # up in bulks for i in range(0, len(memberids), settings.MSSQL_MAX_PARAMETER_COUNT): memberid_chunk = memberids[i:i + settings.MSSQL_MAX_PARAMETER_COUNT] actors = Actor.get_personal_members().filter( memberid__in=memberid_chunk) for actor in actors: cache.set( 'actor.%s' % actor.memberid, actor, settings.FOCUS_MEMBER_CACHE_PERIOD )
def enroll_family_member(self, user_data): """Enroll the given user and add them to this users' family membership. user_data is a dict with the following keys: - first_name - last_name - dob - gender - phone - email""" try: focus_service = suds.client.Client(settings.FOCUS_WSDL_URL) # Use a kwargs dictionary to avoid SyntaxError with non-ascii unicode characters for parameter names params = { 'Token': settings.FOCUS_WSDL_TOKEN, 'Hovedmedlem': self.actor.memberid, 'Husstandsnummer': 0, 'Fornavn': user_data['first_name'], 'Etternavn': user_data['last_name'], 'Født': datetime( year=user_data['dob'].year, month=user_data['dob'].month, day=user_data['dob'].day, ), 'Kjonn': Actor.convert_gender(user_data['gender']), 'Mobil': user_data['phone'], 'Epost': user_data['email'], 'Gjensidige': user_data['accepts_partneroffers'], } result = focus_service.service.EndreHusstand(**params) if result != 'OK': raise Exception("Unknown Focus Webservice result '%s'" % result) except: logger.warning( "Feil med Focus webtjeneste", exc_info=sys.exc_info(), extra={ 'member': self, 'user_data': user_data, }, ) raise FocusServiceError
def get_queryset(self): # This method uses Focus and local users to compile a search result # containing valid turledere. # See the comment on the class definition of the lazy_queryset variable if self.lazy_queryset: return self.lazy_queryset SEARCH_MAX_HITS = 100 search = self.request.query_params.get('search', '').strip() local_nonmember_users = User.get_users().filter(memberid__isnull=True) for word in search.split(): local_nonmember_users = local_nonmember_users.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) ) local_nonmember_users = local_nonmember_users.order_by('first_name') actors = Actor.get_personal_members() for word in search.split(): actors = actors.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) | Q(memberid__icontains=word) ) actors = actors.order_by('first_name') # Get (or create) the user objects for the first MAX_HITS actor-hits users = [ User.get_or_create_inactive(a.memberid) for a in actors[:SEARCH_MAX_HITS]] # Merge with non-members users = sorted( list(users) + list(local_nonmember_users), key=lambda u: u.get_full_name()) self.lazy_queryset = users return users
def validate_existing(enrollment): try: actor = Actor.get_personal_members().get(memberid=enrollment.existing_memberid) except (Actor.DoesNotExist, ValueError): return False if not actor.has_paid(): return False if datetime.now().year - actor.birth_date.year < AGE_YOUTH: return False if actor.is_household_member(): return False if actor.get_clean_address().country.code != enrollment.country: return False if enrollment.country == 'NO' and actor.get_clean_address().zipcode.zipcode != enrollment.zipcode: return False return True
def existing(request): if not request.is_ajax(): return redirect('enrollment.views.household') # Note: This logic is duplicated in validate_existing() data = json.loads(request.POST['data']) if data['country'] == 'NO' and len(data['zipcode']) != 4: return HttpResponse(json.dumps({'error': 'bad_zipcode'})) try: actor = Actor.get_personal_members().get(memberid=data['id']) except Actor.DoesNotExist: return HttpResponse(json.dumps({'error': 'actor.does_not_exist'})) except ValueError: return HttpResponse(json.dumps({'error': 'invalid_id'})) try: if data['country'] == 'NO': # Include zipcode for norwegian members address = ActorAddress.objects.get(actor=actor.id, zipcode=data['zipcode'], country_code=data['country']) else: address = ActorAddress.objects.get(actor=actor.id, country_code=data['country']) except ActorAddress.DoesNotExist: return HttpResponse(json.dumps({'error': 'actoraddress.does_not_exist'})) if not actor.has_paid(): return HttpResponse(json.dumps({'error': 'actor.has_not_paid'})) age = datetime.now().year - actor.birth_date.year if age < AGE_YOUTH: return HttpResponse(json.dumps({'error': 'actor.too_young', 'age': age})) if actor.is_household_member(): return HttpResponse(json.dumps({'error': 'actor.is_household_member'})) return HttpResponse(json.dumps({ 'name': "%s %s" % (actor.first_name, actor.last_name), 'address': address.a1 }))
def get_children_pending(self): """Returns existing single members who are *due to become* family members in this users' family""" from user.models import User children_pending = cache.get('actor.%s.children_pending' % self.actor.memberid) if children_pending is None: actors = Actor.get_personal_members().filter( pending_family_parent=self.actor.memberid, ).exclude( memberid=self.actor.memberid, ).exclude( # Exclude any actual family members. This is necessary because Focus doesn't clear the appropriate # fields when converting pending family members to actual family members. Q(services__code=get_membership_type_by_codename('family_household')['code']) | Q(services__code=get_membership_type_by_codename('family_primary')['code']) ).order_by('first_name', 'last_name') children_pending = [User.get_or_create_inactive(memberid=actor.memberid) for actor in actors] cache.set( 'actor.%s.children_pending' % self.actor.memberid, children_pending, settings.FOCUS_MEMBER_CACHE_PERIOD, ) return children_pending
def member_search(request): if len(request.POST['query']) < settings.ADMIN_USER_SEARCH_CHAR_LENGTH: raise PermissionDenied local_users = User.get_users().filter(memberid__isnull=True) for word in request.POST['query'].split(): local_users = local_users.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) ) local_users = local_users.order_by('first_name') actors = Actor.get_personal_members() for word in request.POST['query'].split(): actors = actors.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) | Q(memberid__icontains=word) ) actors = actors.order_by('first_name') users = User.get_users().filter(memberid__in=[a.memberid for a in actors]) memberids = [u.memberid for u in users] actors_without_user = [a for a in actors if a.memberid not in memberids] # To sort users by name, we need the Actor data - go through the already-fetched bulk and cache them for actor in actors: cache.set('actor.%s' % actor.memberid, actor, settings.FOCUS_MEMBER_CACHE_PERIOD) users = sorted(users, key=lambda u: u.get_full_name()) context = { 'users': users, 'actors_without_user': actors_without_user, 'local_users': local_users, } return HttpResponse(render_to_string('central/admin/turledere/member_search_results.html', context, request=request))
def turleder_search(request): MAX_HITS = 100 if len(request.POST['q']) < settings.ADMIN_USER_SEARCH_CHAR_LENGTH: raise PermissionDenied local_nonmember_users = User.get_users().filter(memberid__isnull=True) for word in request.POST['q'].split(): local_nonmember_users = local_nonmember_users.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) ) local_nonmember_users = local_nonmember_users.order_by('first_name') actors = Actor.get_personal_members() for word in request.POST['q'].split(): actors = actors.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) | Q(memberid__icontains=word) ) actors = actors.order_by('first_name') # Get (or create) the user objects for the first MAX_HITS actor-hits users = [User.get_or_create_inactive(a.memberid) for a in actors[:MAX_HITS]] # Merge with non-members users = sorted(list(users) + list(local_nonmember_users), key=lambda u: u.get_full_name()) context = RequestContext(request, { 'users': users[:MAX_HITS] }) return HttpResponse(json.dumps({ 'results': render_to_string('common/admin/aktiviteter/edit/turleder_search_results.html', context), 'max_hits_exceeded': len(users) > MAX_HITS or len(actors) > MAX_HITS }))
def search(request): if not request.is_ajax() or request.method != 'POST': return redirect('admin:users.index') if len(request.POST['q']) < settings.ADMIN_USER_SEARCH_CHAR_LENGTH: raise PermissionDenied SEARCH_MAX_HITS = 40 local_users = User.get_users().filter( memberid__isnull=True, ).prefetch_related( 'permissions', ) for word in request.POST['q'].split(): local_users = local_users.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) | Q(email__icontains=word) ) local_users = local_users.order_by('first_name')[:SEARCH_MAX_HITS] actors = Actor.get_personal_members().select_related('address', 'address__zipcode') for word in request.POST['q'].split(): actors = actors.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) | Q(email__icontains=word) | Q(memberid__icontains=word) ) actors = actors.order_by('first_name')[:SEARCH_MAX_HITS] # Cache all the actor objects because we will be accessing them through user objects later Actor.cache_all(actors) # Match expired users only on memberid expired_users = User.objects.all() for word in request.POST['q'].split(): expired_users = expired_users.filter(memberid__icontains=word) expired_users = [ u for u in expired_users if not Actor.get_personal_members().only('id').filter(memberid=u.memberid).exists() and not Enrollment.get_active().only('id').filter(memberid=u.memberid).exists() ] # Pending users pending_enrollment = Enrollment.get_active() for word in request.POST['q'].split(): pending_enrollment = pending_enrollment.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) | Q(memberid__icontains=word) ) pending_enrollment = pending_enrollment.order_by('first_name')[:SEARCH_MAX_HITS] max_hits_exceeded = len(local_users) >= SEARCH_MAX_HITS or \ len(actors) >= SEARCH_MAX_HITS or \ len(pending_enrollment) >= SEARCH_MAX_HITS members = User.get_users().filter( memberid__in=[a.memberid for a in actors], ).prefetch_related( 'permissions', ) user_member_ids = list(members.values_list('memberid', flat=True)) pending_users = User.get_users(include_pending=True).filter(memberid__in=[e.memberid for e in pending_enrollment]) actors_without_user = [a for a in actors if a.memberid not in user_member_ids] users = list(local_users) + list(members) + list(pending_users) context = { 'users': users, 'actors_without_user': actors_without_user, 'expired_users': expired_users, 'max_hits_exceeded': max_hits_exceeded, } return HttpResponse(render_to_string('central/admin/users/user_results.html', context, request=request))
def authenticate_users(email, password): """ Yup, this is a 'util' method instead of a proper authentication backend. The reason for this is that as our membersystem allows duplicate email fields, a user can potentially authenticate herself for multiple accounts, and the Django auth backend system doesn't account for that (it returns exactly one user, or None). """ email = email.strip() # Support this special case explicitly because it will hit a lot of Actors # and check for a matching User for each of them, which takes a long time if email == '': return [] # Add matching local users that aren't members matches = [ u for u in User.get_users().filter( memberid__isnull=True, email__iexact=email ) if u.check_password(password) ] # Add matching members in Actor for actor in Actor.get_personal_members().filter(email__iexact=email): try: # Ok, look for any matching active user user = User.get_users( include_pending=True, include_expired=True ).get( memberid=actor.memberid, is_inactive=False # ignore inactive users ) # Reset state if this user was previously pending but is now a # proper member if user.is_pending: user.is_pending = False user.save() # Reset state if this user was previously marked as expired for # some reason if user.is_expired: user.is_expired = False user.save() # Now perform the password check for authentication if user.check_password(password): matches.append(user) except User.DoesNotExist: pass # Add matching pending members for enrollment in Enrollment.filter_on_email(email): try: # Ok, look for any matching active AND pending user user = User.get_users( include_pending=True, include_expired=True ).get( memberid=enrollment.memberid, is_pending=True, is_inactive=False # ignore inactive users ) # Reset state if this user was previously marked as expired for # some reason if user.is_expired: user.is_expired = False user.save() # Now perform the password check for authentication # Check that the user isn't already matched as an Actor since this # theoretically could be a duplicate if user.check_password(password) and user not in matches: matches.append(user) except User.DoesNotExist: pass # And just return these matches return matches
def users(request, forening_id): current_forening = Forening.objects.get(id=forening_id) if current_forening not in request.user.all_foreninger(): raise PermissionDenied p_name = 'sherpa/association/user' prefetch_related = ( 'user_permission_grants', 'user_permission_grants__user_permission', # This is to avoid multiple extra queries from # user.get_permissions_cached() when we check for admin # permission below. 'user_permission_grants__user_permission__oauth_applications', ) forening_users = list( User.objects.filter( user_permission_grants__user_permission__name=p_name, user_permission_grants__association=current_forening ).prefetch_related(*prefetch_related) ) forening_users_by_parent = [] parent_ids = [p.id for p in current_forening.get_parents_deep()] forening_users_by_parent_all = list( User.objects.filter( user_permission_grants__user_permission__name=p_name, user_permission_grants__association__in=parent_ids ).prefetch_related(*prefetch_related) ) # Prefetch and cache the actors memberids = [ u.memberid for u in (forening_users + forening_users_by_parent)] actors = Actor.get_personal_members().filter( memberid__in=memberids, ).prefetch_related( 'services', ) Actor.cache_all(actors) # Safe to iterate without having n+1 issues # Filter on admins forening_users_by_parent = [] for user in forening_users_by_parent_all: for forening in user.all_foreninger(): if forening == current_forening and forening.role == 'admin': forening_users_by_parent.append(user) forening_users = sorted( forening_users, key=lambda u: u.get_full_name(True) ) forening_users_by_parent = sorted( forening_users_by_parent, key=lambda u: u.get_full_name(True) ) context = { 'is_admin_in_forening': request.user.is_admin_in_forening(current_forening), 'current_forening': current_forening, 'forening_users': forening_users, 'forening_users_by_parent': forening_users_by_parent, 'admin_user_search_char_length': ( settings.ADMIN_USER_SEARCH_CHAR_LENGTH ), } return render(request, 'central/admin/foreninger/users.html', context)
def send_restore_password_email(request): if 'email' not in request.POST: raise PermissionDenied email = request.POST['email'].strip() if not validator.email(email): return HttpResponse(json.dumps({'status': 'invalid_email'})) # The address might match one non-member, check it: local_matches = list(User.objects.filter(memberid__isnull=True, email=email)) # The address might match several members, registered or not focus_unregistered_matches = False # Search through matching Actors for actor in Actor.get_personal_members().filter(email=email): try: # Ok, look for any matching active user user = User.get_users( include_pending=True, include_expired=True ).get( memberid=actor.memberid, is_inactive=False # ignore inactive users; these need to register first ) # Reset state if this user was previously pending but is now a proper member if user.is_pending: user.is_pending = False user.save() # Reset state if this user was previously marked as expired for some reason if user.is_expired: user.is_expired = False user.save() local_matches.append(user) except User.DoesNotExist: # There is an actor but no corresponding user - inform the user that they need to register focus_unregistered_matches = True # Now search through matching active enrollments for enrollment in Enrollment.filter_on_email(email): try: # Ok, look for any matching active AND pending user user = User.get_users( include_pending=True, include_expired=True ).get( memberid=enrollment.memberid, is_pending=True, is_inactive=False # ignore inactive users; these need to register first ) # Reset state if this user was previously marked as expired for some reason if user.is_expired: user.is_expired = False user.save() # Check that the user isn't already matched as an Actor since this theoretically could be a duplicate if user not in local_matches: local_matches.append(user) except User.DoesNotExist: pass if len(local_matches) == 0: # No email-address matches. if focus_unregistered_matches: # Oh, the email address exists in Focus, but the user(s) aren't in our user-base. Let them know. return HttpResponse(json.dumps({'status': 'unregistered_email'})) else: return HttpResponse(json.dumps({'status': 'unknown_email'})) else: for user in local_matches: key = crypto.get_random_string(length=settings.RESTORE_PASSWORD_KEY_LENGTH) while User.objects.filter(password_restore_key=key).exists(): # Ensure that the key isn't already in use. With the current key length of 40, we'll have # ~238 bits of entropy which means that this will never ever happen, ever. # You will win the lottery before this happens. And I want to know if it does, so log it. logger.warning( "Noen fikk en random-generert password-restore-key som allerede finnes!", extra={ 'request': request, 'should_you_play_the_lottery': True, 'key': key } ) key = crypto.get_random_string(length=settings.RESTORE_PASSWORD_KEY_LENGTH) user.password_restore_key = key user.password_restore_date = datetime.now() user.save() if len(local_matches) == 1: context = { 'found_user': user, 'validity_period': settings.RESTORE_PASSWORD_VALIDITY, } message = render_to_string('common/user/login/restore-password-email.txt', context, request=request) else: context = { 'users': local_matches, 'validity_period': settings.RESTORE_PASSWORD_VALIDITY, } message = render_to_string( 'common/user/login/restore-password-email-multiple.txt', context, request=request, ) send_mail("Nytt passord på Min side", message, settings.DEFAULT_FROM_EMAIL, [email]) return HttpResponse(json.dumps({'status': 'success'}))
def handle(self, *args, **options): t1 = time.time() task_log = TaskLog.objects.create( thread=str(uuid4()), data={'started': str(datetime.now())}, name='update-user-status', ) members = User.objects.filter(memberid__isnull=False) pending_users = members.filter(is_pending=True) normal_users = members.filter(is_pending=False) task_log.data['pending_users'] = pending_users.count() task_log.data['normal_users'] = normal_users.count() task_log.data['update_pending_count'] = 0 task_log.data['reclaim_for_pending_user_count'] = 0 task_log.data['expire_users_count'] = 0 task_log.save() # Check for pending users that recently got their Actor, and shouldn't # be pending i = 1 for u in pending_users.filter(is_expired=False): i += 1 # This method automatically updates the user if not pending anymore u.verify_still_pending(ignore_cache=True) if not (i % 1000): task_log.data['update_pending_count'] = i task_log.save() task_log.data['update_pending_count'] = i task_log.data['update_pending_done'] = str(datetime.now()) task_log.save() # Check for expired pending users that may have gotten their Actor or # Enrollment object back (doesn't make sense that this actually # happens, but let's not make assumptions for Focus) i = 0 for u in pending_users.filter(is_expired=True): i += 1 if Actor.get_personal_members().filter( memberid=u.memberid).exists(): u.is_expired = False u.is_pending = False u.save() elif Enrollment.objects.filter(memberid=u.memberid).exists(): u.is_expired = False u.save() if not (i % 1000): task_log.data['reclaim_for_pending_user_count'] = i task_log.save() task_log.data['reclaim_for_pending_user_count'] = i task_log.data['reclaim_for_pending_user_done'] = str(datetime.now()) task_log.save() # Check for normal expired users that regained their Actor and # shouldn't be expired anymore for u in normal_users.filter(is_expired=True): if Actor.get_personal_members().filter( memberid=u.memberid).exists(): u.is_expired = False u.save() task_log.data['reclaim_for_normal_user_done'] = str(datetime.now()) task_log.save() # Check for normal users that have lost their Actor and should be # expired i = 0 for u in normal_users.filter(is_expired=False): i += 1 if not Actor.get_personal_members().filter( memberid=u.memberid).exists(): u.is_expired = True u.save() if not (i % 1000): task_log.data['expire_users_count'] = i task_log.save() task_log.data['expire_users_count'] = i task_log.data['expire_users_done'] = str(datetime.now()) task_log.data['ended'] = str(datetime.now()) task_log.data['duration'] = time.time() - t1 task_log.complete = True task_log.save()
def get_queryset(self): # This method uses Focus and local users to compile a search result # containing users. # See the comment on the class definition of the lazy_queryset variable if self.lazy_queryset: return self.lazy_queryset SEARCH_MAX_HITS = 100 search = self.request.query_params.get('search', '').strip() if len(search) < settings.ADMIN_USER_SEARCH_CHAR_LENGTH: raise PermissionDenied local_users = User.get_users().filter(memberid__isnull=True) for word in search.split(): local_users = local_users.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) | Q(email__icontains=word)) local_users = local_users.order_by('first_name')[:SEARCH_MAX_HITS] actors = Actor.get_personal_members().select_related( 'address', 'address__zipcode') for word in search.split(): actors = actors.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) | Q(memberid__icontains=word) | Q(email__icontains=word)) actors = actors.order_by('first_name')[:SEARCH_MAX_HITS] # Cache all the actor objects because we will be accessing them through # user objects later Actor.cache_all(actors) # Match expired users only on memberid expired_users = User.objects.all() for word in search.split(): expired_users = expired_users.filter(memberid__icontains=word) expired_users = [ u for u in expired_users if not Actor.get_personal_members().only('id').filter( memberid=u.memberid).exists() and not Enrollment.get_active() .only('id').filter(memberid=u.memberid).exists() ] # Pending users pending_enrollment = Enrollment.get_active() for word in search.split(): pending_enrollment = pending_enrollment.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) | Q(memberid__icontains=word)) pending_enrollment = pending_enrollment.order_by( 'first_name')[:SEARCH_MAX_HITS] members = User.get_users().filter( memberid__in=[a.memberid for a in actors]) user_member_ids = list(members.values_list('memberid', flat=True)) pending_users = User.get_users(include_pending=True).filter( memberid__in=[e.memberid for e in pending_enrollment]) # Create inactive users for any actor hit without a corresponding user newly_created_members = [ User.get_or_create_inactive(memberid=a.memberid) for a in actors if a.memberid not in user_member_ids ] users = sorted( list(local_users) + list(members) + list(pending_users) + list(newly_created_members), key=lambda u: u.get_full_name()) self.lazy_queryset = users return users
def index(request): total_membership_count = cache.get('admin.total_membership_count') local_membership_count = cache.get('admin.local_membership_count.%s' % request.active_forening.id) if total_membership_count is None or local_membership_count is None: if request.db_connections['focus']['is_available']: all_active_members = Actor.all_active_members() total_membership_count = all_active_members.count() local_membership_count = all_active_members.filter( main_forening_id__in=[f.focus_id for f in request.active_forening.get_main_foreninger()], ).count() cache.set('admin.total_membership_count', total_membership_count, 60 * 60 * 12) cache.set('admin.local_membership_count.%s' % request.active_forening.id, local_membership_count, 60 * 60 * 12) else: # Fallback if Focus is down total_membership_count = None local_membership_count = None turledere = cache.get('admin.turleder_count') if turledere is None: turledere = User.get_users().filter(turledere__isnull=False).distinct().count() cache.set('admin.turleder_count', turledere, 60 * 60 * 6) aktiviteter = cache.get('admin.aktivitet_count') if aktiviteter is None: aktiviteter = Aktivitet.objects.filter( Q(forening=request.active_forening) | Q(co_foreninger=request.active_forening), pub_date__lte=date.today(), published=True, private=False, ).count() cache.set('admin.aktivitet_count', aktiviteter, 60 * 60 * 6) dashboard_stats = { 'members': { 'total': "{:,}".format(total_membership_count) if total_membership_count is not None else '?', 'local': "{:,}".format(local_membership_count) if local_membership_count is not None else '?', }, 'turledere': turledere, 'aktiviteter': aktiviteter, } betablog = cache.get('admin.betablog') if betablog is None: try: betablog = [] r = requests.get("http://beta.dnt.no/", params={'feed': 'rss2'}) channel = etree.fromstring(r.content).find('channel') for item in channel.findall('item'): content = item.find('description').text image = None m = re.search('<img.*?src="(.*?)" ', content) if m is not None: image = m.group(1) pub_date = datetime.strptime(item.find('pubDate').text[:-6], "%a, %d %b %Y %H:%M:%S") betablog.append({ 'title': item.find('title').text, 'link': item.find('link').text, 'content': content, 'image': image, 'pub_date': pub_date, }) except (requests.ConnectionError, AttributeError): pass cache.set('admin.betablog', betablog, 60 * 60 * 12) context = { 'betablog': betablog, 'dashboard_stats': dashboard_stats, } return render(request, 'common/admin/dashboard.html', context)
def turleder_search(request): turledere = User.get_users().filter(turledere__isnull=False) if len(request.POST['query']) > 0: if len(request.POST['query']) < settings.ADMIN_USER_SEARCH_CHAR_LENGTH: raise PermissionDenied actors = Actor.get_personal_members() for word in request.POST['query'].split(): actors = actors.filter( Q(first_name__icontains=word) | Q(last_name__icontains=word) | Q(memberid__icontains=word)) turledere = turledere.filter(memberid__in=[a.memberid for a in actors]) # Filter on foreninger where the turleder is active active_foreninger = json.loads(request.POST['turleder_foreninger_active']) if len(active_foreninger) > 0: turledere = turledere.filter(turleder_active_foreninger__in=active_foreninger) turleder_role = request.POST['turleder_role'] if turleder_role != '': if json.loads(request.POST['turleder_role_include']): roles = [] found = False for i in reversed(range(0, len(Turleder.TURLEDER_CHOICES))): if Turleder.TURLEDER_CHOICES[i][0] == turleder_role: found = True if found: roles.append(Turleder.TURLEDER_CHOICES[i][0]) else: roles = [request.POST['turleder_role']] turledere = turledere.filter(turledere__role__in=roles) for role in json.loads(request.POST['instruktor_roles']): turledere = turledere.filter(instruktor__role=role) if json.loads(request.POST['only_kursledere']): turledere = turledere.filter(kursleder__isnull=False) # Filter on certificates approved by some forening forening_approved = None if request.POST['turleder_forening_approved'] != '': forening_approved = Forening.objects.get(id=request.POST['turleder_forening_approved']) turledere = turledere.filter(turledere__forening_approved=forening_approved) # Eliminates duplicate rows from the query results turledere = turledere.distinct() # Store the toal count for current query total_count = turledere.count() # Limit result set to only 40 elements BULK_COUNT = 40 start = int(request.POST['bulk']) * BULK_COUNT end = start + BULK_COUNT turledere = turledere[start:end] # Prefetch result set in one query and cache them to for future use turledere = turledere.prefetch_related('turledere', 'turledere__forening_approved') memberids = [t.memberid for t in turledere if cache.get('actor.%s' % t.memberid) is None] # If we have more than 2100 parameters, MSSQL will cry, so split it up in bulks for i in range(0, len(memberids), settings.MSSQL_MAX_PARAMETER_COUNT): memberid_chunk = memberids[i:i + settings.MSSQL_MAX_PARAMETER_COUNT] for actor in Actor.get_personal_members().filter(memberid__in=memberid_chunk): cache.set('actor.%s' % actor.memberid, actor, settings.FOCUS_MEMBER_CACHE_PERIOD) context = { 'users': turledere, 'first_bulk': request.POST['bulk'] == '0', 'total_count': total_count, 'forening_count': Forening.objects.filter(type='forening').count(), } return HttpResponse(json.dumps({ 'complete': len(turledere) == 0, 'html': render_to_string('central/admin/turledere/turleder_search_results.html', context, request=request) }))
def send_restore_password_email(request): if not 'email' in request.POST: raise PermissionDenied if not validator.email(request.POST['email']): return HttpResponse(json.dumps({'status': 'invalid_email'})) # The address might match one non-member, check it: local_matches = list(User.objects.filter(memberid__isnull=True, email=request.POST['email'])) # The address might match several members, registered or not focus_unregistered_matches = False # Search through matching Actors for actor in Actor.get_personal_members().filter(email=request.POST['email']): try: # Ok, look for any matching active user user = User.get_users( include_pending=True, include_expired=True ).get( memberid=actor.memberid, is_inactive=False # ignore inactive users; these need to register first ) # Reset state if this user was previously pending but is now a proper member if user.is_pending: user.is_pending = False user.save() # Reset state if this user was previously marked as expired for some reason if user.is_expired: user.is_expired = False user.save() local_matches.append(user) except User.DoesNotExist: # There is an actor but no corresponding user - inform the user that they need to register focus_unregistered_matches = True # Now search through matching active enrollments for enrollment in get_enrollment_email_matches(request.POST['email']): try: # Ok, look for any matching active AND pending user user = User.get_users( include_pending=True, include_expired=True ).get( memberid=enrollment.memberid, is_pending=True, is_inactive=False # ignore inactive users; these need to register first ) # Reset state if this user was previously marked as expired for some reason if user.is_expired: user.is_expired = False user.save() # Check that the user isn't already matched as an Actor since this theoretically could be a duplicate if user not in local_matches: local_matches.append(user) except User.DoesNotExist: pass # Check for matching old user system members - we'll generate a password so that they can login and be imported all_sherpa2_matches = Member.objects.filter(email=request.POST['email']) # Include expired users when excluding sherpa2 matches - if their current user object is expired, # it's irrelevant whether or not the old user account matches sherpa2_matches = [m for m in all_sherpa2_matches if not User.objects.filter(memberid=m.memberid, is_inactive=False).exists()] if len(local_matches) == 0 and len(sherpa2_matches) == 0: # No email-address matches. if focus_unregistered_matches: # Oh, the email address exists in Focus, but the user(s) aren't in our user-base. Let them know. return HttpResponse(json.dumps({'status': 'unregistered_email'})) else: return HttpResponse(json.dumps({'status': 'unknown_email'})) if len(sherpa2_matches) > 0: for member in sherpa2_matches: sha1 = hashlib.sha1() new_password = crypto.get_random_string(length=10) sha1.update(new_password) member.password = sha1.hexdigest() member.save() t = loader.get_template('common/user/login/restore-password-email-sherpa25.txt') c = RequestContext(request, { 'member': member, 'new_password': new_password }) send_mail("Nytt passord på Min side", t.render(c), settings.DEFAULT_FROM_EMAIL, [request.POST['email']]) if len(local_matches) > 0: for user in local_matches: key = crypto.get_random_string(length=settings.RESTORE_PASSWORD_KEY_LENGTH) while User.objects.filter(password_restore_key=key).exists(): # Ensure that the key isn't already in use. With the current key length of 40, we'll have # ~238 bits of entropy which means that this will never ever happen, ever. # You will win the lottery before this happens. And I want to know if it does, so log it. logger.warning(u"Noen fikk en random-generert password-restore-key som allerede finnes!", extra={ 'request': request, 'should_you_play_the_lottery': True, 'key': key } ) key = crypto.get_random_string(length=settings.RESTORE_PASSWORD_KEY_LENGTH) user.password_restore_key = key user.password_restore_date = datetime.now() user.save() if len(local_matches) == 1: t = loader.get_template('common/user/login/restore-password-email.txt') c = RequestContext(request, { 'found_user': user, 'validity_period': settings.RESTORE_PASSWORD_VALIDITY }) else: t = loader.get_template('common/user/login/restore-password-email-multiple.txt') c = RequestContext(request, { 'users': local_matches, 'validity_period': settings.RESTORE_PASSWORD_VALIDITY }) send_mail("Nytt passord på Min side", t.render(c), settings.DEFAULT_FROM_EMAIL, [request.POST['email']]) return HttpResponse(json.dumps({'status': 'success'}))