Пример #1
0
    def prepare_context(self, program, target_path=None):
        context = {}
        context['program'] = program
        context['user_types'] = ESPUser.getTypes()
        category_lists = {}
        list_descriptions = program.getListDescriptions()

        #   Add in program-specific lists for most common user types
        for user_type, list_func in zip(Program.USER_TYPES_WITH_LIST_FUNCS,
                                        Program.USER_TYPE_LIST_FUNCS):
            raw_lists = getattr(program, list_func)(True)
            category_lists[user_type] = [{
                'name': key,
                'list': raw_lists[key],
                'description': list_descriptions[key]
            } for key in raw_lists]
            for item in category_lists[user_type]:
                if item['name'] in UserSearchController.preferred_lists:
                    item['preferred'] = True

        #   Add in global lists for each user type
        for user_type in ESPUser.getTypes():
            key = user_type.lower() + 's'
            if user_type not in category_lists:
                category_lists[user_type] = []
            category_lists[user_type].insert(
                0, {
                    'name': 'all_%s' % user_type,
                    'list': ESPUser.getAllOfType(user_type),
                    'description': 'All %s in the database' % key,
                    'preferred': True,
                    'all_flag': True
                })

        #   Add in mailing list accounts
        category_lists['emaillist'] = [{
            'name': 'all_emaillist',
            'list': Q(password='******'),
            'description': 'Everyone signed up for the mailing list',
            'preferred': True
        }]

        context['lists'] = category_lists
        context['all_list_names'] = []
        for category in category_lists:
            for item in category_lists[category]:
                context['all_list_names'].append(item['name'])

        if target_path is None:
            target_path = '/manage/%s/commpanel' % program.getUrlBase()
        context['action_path'] = target_path
        context['groups'] = Group.objects.all()

        return context
Пример #2
0
    def gen_perm(tup):
        new_perm=Permission(permission_type=tup[0], program=prog)

        if tup[2]:
            new_perm.start_date = tup[2]
        if tup[3]:
            new_perm.end_date = tup[3]

        if tup[1] is not None:
            new_perm.user=tup[1]
            new_perm.save()
            return
        elif tup[1] is None and tup[0].startswith("Student"):
            new_perm.role=Group.objects.get(name="Student")
            new_perm.save()
            return
        elif tup[1] is None and tup[0].startswith("Teacher"):
            new_perm.role=Group.objects.get(name="Teacher")
            new_perm.save()
            return

        #It's not for a specific user and not a teacher or student deadline
        for x in ESPUser.getTypes():
            newnew_perm=Permission(permission_type=new_perm.permission_type, role=Group.objects.get(name=x), start_date=new_perm.start_date, end_date=new_perm.end_date, program=prog)
            newnew_perm.save()
Пример #3
0
    def gen_perm(tup):
        new_perm = Permission(permission_type=tup[0], program=prog)

        if tup[2]:
            new_perm.start_date = tup[2]
        if tup[3]:
            new_perm.end_date = tup[3]

        if tup[1] is not None:
            new_perm.user = tup[1]
            new_perm.save()
            return
        elif tup[1] is None and tup[0].startswith("Student"):
            new_perm.role = Group.objects.get(name="Student")
            new_perm.save()
            return
        elif tup[1] is None and tup[0].startswith("Teacher"):
            new_perm.role = Group.objects.get(name="Teacher")
            new_perm.save()
            return

        #It's not for a specific user and not a teacher or student deadline
        for x in ESPUser.getTypes():
            newnew_perm = Permission(permission_type=new_perm.permission_type,
                                     role=Group.objects.get(name=x),
                                     start_date=new_perm.start_date,
                                     end_date=new_perm.end_date,
                                     program=prog)
            newnew_perm.save()
Пример #4
0
    def prepare_context(self, program, target_path=None):
        context = {}
        context['program'] = program
        context['user_types'] = ESPUser.getTypes()
        category_lists = {}
        list_descriptions = program.getListDescriptions()

        #   Add in program-specific lists for most common user types
        for user_type, list_func in zip(Program.USER_TYPES_WITH_LIST_FUNCS, Program.USER_TYPE_LIST_FUNCS):
            raw_lists = getattr(program, list_func)(True)
            category_lists[user_type] = [{'name': key, 'list': raw_lists[key], 'description': list_descriptions[key]} for key in raw_lists]
            for item in category_lists[user_type]:
                if item['name'] in UserSearchController.preferred_lists:
                    item['preferred'] = True

        #   Add in global lists for each user type
        for user_type in ESPUser.getTypes():
            key = user_type.lower() + 's'
            if user_type not in category_lists:
                category_lists[user_type] = []
            category_lists[user_type].insert(0, {'name': 'all_%s' % user_type, 'list': ESPUser.getAllOfType(user_type), 'description': 'All %s in the database' % key, 'preferred': True, 'all_flag': True})

        #   Add in mailing list accounts
        category_lists['emaillist'] = [{'name': 'all_emaillist', 'list': Q(password = '******'), 'description': 'Everyone signed up for the mailing list', 'preferred': True}]

        context['lists'] = category_lists
        context['all_list_names'] = []
        for category in category_lists:
            for item in category_lists[category]:
                context['all_list_names'].append(item['name'])

        if target_path is None:
            target_path = '/manage/%s/commpanel' % program.getUrlBase()
        context['action_path'] = target_path

        return context
    def forwards(self, orm):
        def end(bit):
            date = bit.enddate
            if date > datetime.datetime(3000, 1, 1):
                return None
            return date

        #Administer
        adm_bits = orm['users.UserBit'].objects.filter(
            verb__uri="V/Administer", qsc__uri__startswith="Q/Programs")
        for bit in adm_bits:
            try:
                p = orm['program.Program'].objects.get(anchor=bit.qsc)
            except orm['program.Program'].DoesNotExist:
                continue
            orm['users.Permission'](permission_type="Administer",
                                    program=p,
                                    user=bit.user,
                                    startdate=bit.startdate,
                                    enddate=end(bit)).save()

        # Administer all programs, but with an enddate.
        # Adds users that we didn't add to the Administrator group in 0019_userrole.
        for bit in orm['users.UserBit'].objects.filter(
                verb__uri="V/Administer",
                qsc__uri="Q",
                user__isnull=False,
                enddate__lt=datetime.datetime(3000, 1, 1)):
            orm['users.Permission'](permission_type="Administer",
                                    program=None,
                                    user=bit.user,
                                    startdate=bit.startdate,
                                    enddate=end(bit)).save()

        #view programs
        program_anchors = orm['program.Program'].objects.all().values_list(
            "anchor", flat=True)
        view_program_bits = orm['users.UserBit'].objects.filter(
            verb__uri="V/Flags/Public", qsc__id__in=program_anchors)
        for bit in view_program_bits:
            try:
                p = orm['program.Program'].objects.get(anchor=bit.qsc)
            except orm['program.Program'].DoesNotExist:
                continue
            if bit.user is not None:
                orm['users.Permission'](permission_type=bit.verb.uri[24:],
                                        user=bit.user,
                                        program=p,
                                        startdate=bit.startdate,
                                        enddate=end(bit)).save()
            else:
                for x in ESPUser.getTypes():
                    orm['users.Permission'](
                        permission_type=bit.verb.uri[24:],
                        role=orm['auth.Group'].objects.get(name=x),
                        program=p,
                        startdate=bit.startdate,
                        enddate=end(bit)).save()

        #gradeoverride
        go_bits = orm['users.UserBit'].objects.filter(
            verb__uri="V/Flags/Registration/GradeOverride",
            qsc__uri__startswith="Q/Programs")
        for bit in go_bits:
            try:
                p = orm['program.Program'].objects.get(anchor=bit.qsc)
            except orm['program.Program'].DoesNotExist:
                continue
            orm['users.Permission'](permission_type="GradeOverride",
                                    program=p,
                                    user=bit.user,
                                    startdate=bit.startdate,
                                    enddate=end(bit)).save()

        #onsite
        onsite_bits = orm['users.UserBit'].objects.filter(
            verb__uri="V/Registration/Onsite")
        for bit in onsite_bits:
            try:
                p = orm['program.Program'].objects.get(anchor=bit.qsc)
            except orm['program.Program'].DoesNotExist:
                continue
            orm['users.Permission'](permission_type="Onsite",
                                    user=bit.user,
                                    program=p,
                                    startdate=bit.startdate,
                                    enddate=end(bit)).save()

        #deadlines
        deadline_bits = orm['users.UserBit'].objects.filter(
            verb__uri__startswith="V/Deadline/Registration")
        for bit in deadline_bits:
            try:
                p = orm['program.Program'].objects.get(anchor=bit.qsc)
            except orm['program.Program'].DoesNotExist:
                continue

            name = bit.verb.uri[24:]
            if bit.recursive and bit.verb.name in [
                    "Classes", "Teacher", "Student"
            ]:
                name += "/All"
            if bit.user is not None:
                orm['users.Permission'](permission_type=name,
                                        user=bit.user,
                                        program=p,
                                        startdate=bit.startdate,
                                        enddate=end(bit)).save()
            elif bit.verb.uri[24:31] == "Teacher":
                orm['users.Permission'](
                    permission_type=name,
                    role=orm['auth.Group'].objects.get(name="Teacher"),
                    program=p,
                    startdate=bit.startdate,
                    enddate=end(bit)).save()
            elif bit.verb.uri[24:31] == "Student":
                orm['users.Permission'](
                    permission_type=name,
                    role=orm['auth.Group'].objects.get(name="Student"),
                    program=p,
                    startdate=bit.startdate,
                    enddate=end(bit)).save()
Пример #6
0
    def query_from_criteria(self, user_type, criteria):
        """ Get the "base list" consisting of all the users of a specific type. """
        if user_type.lower() == 'any':
            Q_base = Q()
        else:
            if user_type not in ESPUser.getTypes():
                raise ESPUser(), 'user_type must be one of ' + str(
                    ESPUser.getTypes())
            Q_base = ESPUser.getAllOfType(user_type, True)

        Q_include = Q()
        Q_exclude = Q()
        """ Apply the specified criteria to filter the list of users. """
        if criteria.has_key('userid') and len(criteria['userid'].strip()) > 0:

            ##  Select users based on their IDs only
            userid = []
            for digit in criteria['userid'].split(','):
                try:
                    userid.append(int(digit))
                except:
                    raise ESPError(
                        False
                    ), 'User id invalid, please enter a number or comma-separated list of numbers.'

            if criteria.has_key('userid__not'):
                Q_exclude &= Q(id__in=userid)
            else:
                Q_include &= Q(id__in=userid)
            self.updated = True

        else:

            ##  Select users based on all other criteria that was entered
            for field in ['username', 'last_name', 'first_name', 'email']:
                if criteria.has_key(field) and len(
                        criteria[field].strip()) > 0:
                    #   Check that it's a valid regular expression
                    try:
                        rc = re.compile(criteria[field])
                    except:
                        raise ESPError(
                            False
                        ), 'Invalid search expression, please check your syntax: %s' % criteria[
                            field]
                    filter_dict = {'%s__iregex' % field: criteria[field]}
                    if criteria.has_key('%s__not' % field):
                        Q_exclude &= Q(**filter_dict)
                    else:
                        Q_include &= Q(**filter_dict)
                    self.updated = True

            if criteria.has_key('zipcode') and criteria.has_key('zipdistance') and \
                len(criteria['zipcode'].strip()) > 0 and len(criteria['zipdistance'].strip()) > 0:
                try:
                    zipc = ZipCode.objects.get(zip_code=criteria['zipcode'])
                except:
                    raise ESPError(
                        False
                    ), 'Zip code not found.  This may be because you didn\'t enter a valid US zipcode.  Tried: "%s"' % criteria[
                        'zipcode']
                zipcodes = zipc.close_zipcodes(criteria['zipdistance'])
                # Excludes zipcodes within a certain radius, giving an annulus; can fail to exclude people who used to live outside the radius.
                # This may have something to do with the Q_include line below taking more than just the most recent profile. -ageng, 2008-01-15
                if criteria.has_key('zipdistance_exclude') and len(
                        criteria['zipdistance_exclude'].strip()) > 0:
                    zipcodes_exclude = zipc.close_zipcodes(
                        criteria['zipdistance_exclude'])
                    zipcodes = [
                        zipcode for zipcode in zipcodes
                        if zipcode not in zipcodes_exclude
                    ]
                if len(zipcodes) > 0:
                    Q_include &= Q(
                        registrationprofile__contact_user__address_zip__in=
                        zipcodes,
                        registrationprofile__most_recent_profile=True)
                    self.updated = True

            if criteria.has_key('states') and len(
                    criteria['states'].strip()) > 0:
                state_codes = criteria['states'].strip().upper().split(',')
                if criteria.has_key('states__not'):
                    Q_exclude &= Q(
                        registrationprofile__contact_user__address_state__in=
                        state_codes,
                        registrationprofile__most_recent_profile=True)
                else:
                    Q_include &= Q(
                        registrationprofile__contact_user__address_state__in=
                        state_codes,
                        registrationprofile__most_recent_profile=True)
                self.updated = True

            if criteria.has_key('grade_min'):
                yog = ESPUser.YOGFromGrade(criteria['grade_min'])
                if yog != 0:
                    Q_include &= Q(
                        registrationprofile__student_info__graduation_year__lte
                        =yog,
                        registrationprofile__most_recent_profile=True)
                    self.updated = True

            if criteria.has_key('grade_max'):
                yog = ESPUser.YOGFromGrade(criteria['grade_max'])
                if yog != 0:
                    Q_include &= Q(
                        registrationprofile__student_info__graduation_year__gte
                        =yog,
                        registrationprofile__most_recent_profile=True)
                    self.updated = True

            if criteria.has_key('school'):
                school = criteria['school']
                if school:
                    Q_include &= (
                        Q(studentinfo__school__icontains=school)
                        | Q(studentinfo__k12school__name__icontains=school))
                    self.updated = True

            #   Filter by graduation years if specifically looking for teachers.
            possible_gradyears = range(1920, 2020)
            if criteria.has_key('gradyear_min') and len(
                    criteria['gradyear_min'].strip()) > 0:
                try:
                    gradyear_min = int(criteria['gradyear_min'])
                except:
                    raise ESPError(
                        False
                    ), 'Please enter a 4-digit integer for graduation year limits.'
                possible_gradyears = filter(lambda x: x >= gradyear_min,
                                            possible_gradyears)
            if criteria.has_key('gradyear_max') and len(
                    criteria['gradyear_min'].strip()) > 0:
                try:
                    gradyear_max = int(criteria['gradyear_max'])
                except:
                    raise ESPError(
                        False
                    ), 'Please enter a 4-digit integer for graduation year limits.'
                possible_gradyears = filter(lambda x: x <= gradyear_max,
                                            possible_gradyears)
            if criteria.get('gradyear_min', None) or criteria.get(
                    'gradyear_max', None):
                Q_include &= Q(
                    registrationprofile__teacher_info__graduation_year__in=map(
                        str, possible_gradyears),
                    registrationprofile__most_recent_profile=True)
                self.updated = True

        return Q_base & (Q_include & ~Q_exclude)
Пример #7
0
    def query_from_postdata(self, program, data):
        """ Get a Q object for the targeted list of users from the POST data submitted
            on the main "comm panel" page
        """
        def get_recipient_type(list_name):
            for user_type in Program.USER_TYPE_LIST_FUNCS:
                raw_lists = getattr(program, user_type)(True)
                if list_name in raw_lists:
                    return user_type

        if 'base_list' in data and 'recipient_type' in data:
            #   Get the program-specific part of the query (e.g. which list to use)
            if data['recipient_type'] not in ESPUser.getTypes():
                recipient_type = 'any'
                q_program = Q()
            else:
                if data['base_list'].startswith('all'):
                    q_program = Q()
                    recipient_type = data['recipient_type']
                else:
                    program_lists = getattr(
                        program,
                        data['recipient_type'].lower() + 's')(QObjects=True)
                    q_program = program_lists[data['base_list']]
                    """ Some program queries rely on UserBits, and since user types are also stored in
                        UserBits we cannot store both of these in a single Q object.  To compensate, we
                        ignore the user type when performing a program-specific query.  """
                    recipient_type = 'any'

            #   Get the user-specific part of the query (e.g. ID, name, school)
            q_extra = self.query_from_criteria(recipient_type, data)

        ##  Handle "combination list" submissions
        elif 'combo_base_list' in data:
            #   Get an initial query from the supplied base list
            recipient_type, list_name = data['combo_base_list'].split(':')
            if list_name.startswith('all'):
                q_program = Q()
            else:
                q_program = getattr(program,
                                    recipient_type.lower() +
                                    's')(QObjects=True)[list_name]

            #   Apply Boolean filters
            #   Base list will be intersected with any lists marked 'AND', and then unioned
            #   with any lists marked 'OR'.
            checkbox_keys = map(
                lambda x: x[9:],
                filter(lambda x: x.startswith('checkbox_'), data.keys()))
            and_keys = map(
                lambda x: x[4:],
                filter(lambda x: x.startswith('and_'), checkbox_keys))
            or_keys = map(lambda x: x[3:],
                          filter(lambda x: x.startswith('or_'), checkbox_keys))
            not_keys = map(
                lambda x: x[4:],
                filter(lambda x: x.startswith('not_'), checkbox_keys))

            for and_list_name in and_keys:
                user_type = get_recipient_type(and_list_name)
                if user_type:
                    if and_list_name not in not_keys:
                        q_program = q_program & (getattr(
                            program, user_type)(QObjects=True)[and_list_name])
                    else:
                        q_program = q_program & (~getattr(
                            program, user_type)(QObjects=True)[and_list_name])
            for or_list_name in or_keys:
                user_type = get_recipient_type(or_list_name)
                if user_type:
                    if or_list_name not in not_keys:
                        q_program = q_program | (getattr(
                            program, user_type)(QObjects=True)[or_list_name])
                    else:
                        q_program = q_program | (~getattr(program, user_type)
                                                 (QObjects=True)[or_list_name])

            #   Get the user-specific part of the query (e.g. ID, name, school)
            q_extra = self.query_from_criteria(recipient_type, data)

        return (q_extra & q_program & Q(is_active=True))
Пример #8
0
    def query_from_criteria(self, user_type, criteria):

        """ Get the "base list" consisting of all the users of a specific type. """
        if user_type.lower() == 'any':
            Q_base = Q()
        else:
            if user_type not in ESPUser.getTypes():
                raise ESPError('user_type must be one of '+str(ESPUser.getTypes()))
            Q_base = ESPUser.getAllOfType(user_type, True)

        Q_include = Q()
        Q_exclude = Q()

        """ Apply the specified criteria to filter the list of users. """
        if criteria.get('userid', '').strip():

            ##  Select users based on their IDs only
            userid = []
            for digit in criteria['userid'].split(','):
                try:
                    userid.append(int(digit))
                except:
                    raise ESPError('User id invalid, please enter a number or comma-separated list of numbers.', log=False)

            if 'userid__not' in criteria:
                Q_exclude &= Q(id__in = userid)
            else:
                Q_include &= Q(id__in = userid)
            self.updated = True

        else:

            ##  Select users based on all other criteria that was entered
            for field in ['username','last_name','first_name', 'email']:
                if criteria.get(field, '').strip():
                    #   Check that it's a valid regular expression
                    try:
                        rc = re.compile(criteria[field])
                    except:
                        raise ESPError('Invalid search expression, please check your syntax: %s' % criteria[field], log=False)
                    filter_dict = {'%s__iregex' % field: criteria[field]}
                    if '%s__not' % field in criteria:
                        Q_exclude &= Q(**filter_dict)
                    else:
                        Q_include &= Q(**filter_dict)
                    self.updated = True

            if 'zipcode' in criteria and 'zipdistance' in criteria and \
                len(criteria['zipcode'].strip()) > 0 and len(criteria['zipdistance'].strip()) > 0:
                try:
                    zipc = ZipCode.objects.get(zip_code = criteria['zipcode'])
                except:
                    raise ESPError('Zip code not found.  This may be because you didn\'t enter a valid US zipcode.  Tried: "%s"' % criteria['zipcode'], log=False)
                zipcodes = zipc.close_zipcodes(criteria['zipdistance'])
                # Excludes zipcodes within a certain radius, giving an annulus; can fail to exclude people who used to live outside the radius.
                # This may have something to do with the Q_include line below taking more than just the most recent profile. -ageng, 2008-01-15
                if criteria.get('zipdistance_exclude', '').strip():
                    zipcodes_exclude = zipc.close_zipcodes(criteria['zipdistance_exclude'])
                    zipcodes = [ zipcode for zipcode in zipcodes if zipcode not in zipcodes_exclude ]
                if len(zipcodes) > 0:
                    Q_include &= Q(registrationprofile__contact_user__address_zip__in = zipcodes, registrationprofile__most_recent_profile=True)
                    self.updated = True

            if criteria.get('states', '').strip():
                state_codes = criteria['states'].strip().upper().split(',')
                if 'states__not' in criteria:
                    Q_exclude &= Q(registrationprofile__contact_user__address_state__in = state_codes, registrationprofile__most_recent_profile=True)
                else:
                    Q_include &= Q(registrationprofile__contact_user__address_state__in = state_codes, registrationprofile__most_recent_profile=True)
                self.updated = True

            if 'grade_min' in criteria:
                yog = ESPUser.YOGFromGrade(criteria['grade_min'])
                if yog != 0:
                    Q_include &= Q(registrationprofile__student_info__graduation_year__lte = yog, registrationprofile__most_recent_profile=True)
                    self.updated = True

            if 'grade_max' in criteria:
                yog = ESPUser.YOGFromGrade(criteria['grade_max'])
                if yog != 0:
                    Q_include &= Q(registrationprofile__student_info__graduation_year__gte = yog, registrationprofile__most_recent_profile=True)
                    self.updated = True

            if 'school' in criteria:
                school = criteria['school']
                if school:
                    Q_include &= (Q(studentinfo__school__icontains=school) | Q(studentinfo__k12school__name__icontains=school))
                    self.updated = True

            #   Filter by graduation years if specifically looking for teachers.
            possible_gradyears = range(1920, 2020)
            if criteria.get('gradyear_min', '').strip():
                try:
                    gradyear_min = int(criteria['gradyear_min'])
                except:
                    raise ESPError('Please enter a 4-digit integer for graduation year limits.', log=False)
                possible_gradyears = filter(lambda x: x >= gradyear_min, possible_gradyears)
            if criteria.get('gradyear_max', '').strip():
                try:
                    gradyear_max = int(criteria['gradyear_max'])
                except:
                    raise ESPError('Please enter a 4-digit integer for graduation year limits.', log=False)
                possible_gradyears = filter(lambda x: x <= gradyear_max, possible_gradyears)
            if criteria.get('gradyear_min', None) or criteria.get('gradyear_max', None):
                Q_include &= Q(registrationprofile__teacher_info__graduation_year__in = map(str, possible_gradyears), registrationprofile__most_recent_profile=True)
                self.updated = True

        return Q_base & (Q_include & ~Q_exclude)
Пример #9
0
    def query_from_postdata(self, program, data):
        """ Get a Q object for the targeted list of users from the POST data submitted
            on the main "comm panel" page
        """

        def get_recipient_type(list_name):
            for user_type in Program.USER_TYPE_LIST_FUNCS:
                raw_lists = getattr(program, user_type)(True)
                if list_name in raw_lists:
                    return user_type

        subquery = None

        if 'base_list' in data and 'recipient_type' in data:
            #   Get the program-specific part of the query (e.g. which list to use)
            if data['recipient_type'] not in ESPUser.getTypes():
                recipient_type = 'any'
                q_program = Q()
            else:
                if data['base_list'].startswith('all'):
                    q_program = Q()
                    recipient_type = data['recipient_type']
                else:
                    program_lists = getattr(program, data['recipient_type'].lower()+'s')(QObjects=True)
                    q_program = program_lists[data['base_list']]
                    """ Some program queries rely on UserBits, and since user types are also stored in
                        UserBits we cannot store both of these in a single Q object.  To compensate, we
                        ignore the user type when performing a program-specific query.  """
                    recipient_type = 'any'

            #   Get the user-specific part of the query (e.g. ID, name, school)
            q_extra = self.query_from_criteria(recipient_type, data)

        ##  Handle "combination list" submissions
        elif 'combo_base_list' in data:
            #   Get an initial query from the supplied base list
            recipient_type, list_name = data['combo_base_list'].split(':')
            if list_name.startswith('all'):
                q_program = Q()
            else:
                q_program = getattr(program, recipient_type.lower()+'s')(QObjects=True)[list_name]

            #   Apply Boolean filters
            #   Base list will be intersected with any lists marked 'AND', and then unioned
            #   with any lists marked 'OR'.
            checkbox_keys = map(lambda x: x[9:], filter(lambda x: x.startswith('checkbox_'), data.keys()))
            and_keys = map(lambda x: x[4:], filter(lambda x: x.startswith('and_'), checkbox_keys))
            or_keys = map(lambda x: x[3:], filter(lambda x: x.startswith('or_'), checkbox_keys))
            not_keys = map(lambda x: x[4:], filter(lambda x: x.startswith('not_'), checkbox_keys))
            #if any keys concern the same field, we will place them into
            #a subquery and count occurrences

            #for the purpose of experimentation simply fix this to the record__event
            #as this could very well have different implications for other fields

            subqry_fieldmap = {'record__event':[]}

            for and_list_name in and_keys:
                user_type = get_recipient_type(and_list_name)

                if user_type:

                    qobject = getattr(program, user_type)(QObjects=True)[and_list_name]

                    if and_list_name in not_keys:
                        q_program = q_program & ~qobject
                    else:
                        qobject_child = qobject.children[1]
                        needs_subquery = False

                        if isinstance(qobject_child, (list, tuple)):
                            field_name, field_value = qobject.children[1]
                            needs_subquery = field_name in subqry_fieldmap

                            if needs_subquery:
                                subqry_fieldmap[field_name].append(field_value)
                        if not needs_subquery:
                            q_program = q_program & qobject

            event_fields = subqry_fieldmap['record__event']

            if event_fields:
                #annotation is needed to initiate group by
                #except that it causes the query to return two columns
                #so we call values at the end of the chain, however,
                #that results in multiple group by fields(causing the query to fail)
                #so, we assign a group by field, to force grouping by user_id
                subquery = (
                              Record
                              .objects
                              .filter(program=program,event__in=event_fields)
                              .annotate(numusers=Count('user__id'))
                              .filter(numusers=len(event_fields))
                              .values_list('user_id',flat=True)
                            )

                subquery.query.group_by = []#leave empty to strip out duplicate group by
                subquery = Q(pk__in=subquery)

            for or_list_name in or_keys:
                user_type = get_recipient_type(or_list_name)
                if user_type:
                    qobject = getattr(program, user_type)(QObjects=True)[or_list_name]
                    if or_list_name not in not_keys:
                        q_program = q_program | qobject
                    else:
                        q_program = q_program | ~qobject

            #   Get the user-specific part of the query (e.g. ID, name, school)
            q_extra = self.query_from_criteria(recipient_type, data)

        qobject = (q_extra & q_program & Q(is_active=True))

        #strip out duplicate clauses
        #   Note: in some cases, the children of the Q object are unhashable.
        #   Keep these separate.
        clauses_hashable = []
        clauses_unhashable = []
        for clause in qobject.children:
            if isinstance(clause, Q) or (isinstance(clause, tuple) and isinstance(clause[1], collections.Hashable)):
                clauses_hashable.append(clause)
            else:
                clauses_unhashable.append(clause)
        qobject.children = list(set(clauses_hashable)) + clauses_unhashable

        if subquery:
            qobject = qobject & subquery
        return qobject
Пример #10
0
    def query_from_postdata(self, program, data):
        """ Get a Q object for the targeted list of users from the POST data submitted
            on the main "comm panel" page
        """
        def get_recipient_type(list_name):
            for user_type in Program.USER_TYPE_LIST_FUNCS:
                raw_lists = getattr(program, user_type)(True)
                if list_name in raw_lists:
                    return user_type

        subquery = None

        if 'base_list' in data and 'recipient_type' in data:
            #   Get the program-specific part of the query (e.g. which list to use)
            if data['recipient_type'] not in ESPUser.getTypes():
                recipient_type = 'any'
                q_program = Q()
            else:
                if data['base_list'].startswith('all'):
                    q_program = Q()
                    recipient_type = data['recipient_type']
                else:
                    program_lists = getattr(
                        program,
                        data['recipient_type'].lower() + 's')(QObjects=True)
                    q_program = program_lists[data['base_list']]
                    """ Some program queries rely on UserBits, and since user types are also stored in
                        UserBits we cannot store both of these in a single Q object.  To compensate, we
                        ignore the user type when performing a program-specific query.  """
                    recipient_type = 'any'

            #   Get the user-specific part of the query (e.g. ID, name, school)
            q_extra = self.query_from_criteria(recipient_type, data)

        ##  Handle "combination list" submissions
        elif 'combo_base_list' in data:
            #   Get an initial query from the supplied base list
            recipient_type, list_name = data['combo_base_list'].split(':')
            if list_name.startswith('all'):
                q_program = Q()
            else:
                q_program = getattr(program,
                                    recipient_type.lower() +
                                    's')(QObjects=True)[list_name]

            #   Apply Boolean filters
            #   Base list will be intersected with any lists marked 'AND', and then unioned
            #   with any lists marked 'OR'.
            checkbox_keys = map(
                lambda x: x[9:],
                filter(lambda x: x.startswith('checkbox_'), data.keys()))
            and_keys = map(
                lambda x: x[4:],
                filter(lambda x: x.startswith('and_'), checkbox_keys))
            or_keys = map(lambda x: x[3:],
                          filter(lambda x: x.startswith('or_'), checkbox_keys))
            not_keys = map(
                lambda x: x[4:],
                filter(lambda x: x.startswith('not_'), checkbox_keys))
            #if any keys concern the same field, we will place them into
            #a subquery and count occurrences

            #for the purpose of experimentation simply fix this to the record__event
            #as this could very well have different implications for other fields

            subqry_fieldmap = {'record__event': []}

            for and_list_name in and_keys:
                user_type = get_recipient_type(and_list_name)

                if user_type:

                    qobject = getattr(program,
                                      user_type)(QObjects=True)[and_list_name]

                    if and_list_name in not_keys:
                        q_program = q_program & ~qobject
                    else:
                        qobject_child = qobject.children[1]
                        needs_subquery = False

                        if isinstance(qobject_child, (list, tuple)):
                            field_name, field_value = qobject.children[1]
                            needs_subquery = field_name in subqry_fieldmap

                            if needs_subquery:
                                subqry_fieldmap[field_name].append(field_value)
                        if not needs_subquery:
                            q_program = q_program & qobject

            event_fields = subqry_fieldmap['record__event']

            if event_fields:
                #annotation is needed to initiate group by
                #except that it causes the query to return two columns
                #so we call values at the end of the chain, however,
                #that results in multiple group by fields(causing the query to fail)
                #so, we assign a group by field, to force grouping by user_id
                subquery = (Record.objects.filter(
                    program=program, event__in=event_fields).annotate(
                        numusers=Count('user__id')).filter(
                            numusers=len(event_fields)).values_list('user_id',
                                                                    flat=True))

                subquery.query.group_by = [
                ]  #leave empty to strip out duplicate group by
                subquery = Q(pk__in=subquery)

            for or_list_name in or_keys:
                user_type = get_recipient_type(or_list_name)
                if user_type:
                    qobject = getattr(program,
                                      user_type)(QObjects=True)[or_list_name]
                    if or_list_name not in not_keys:
                        q_program = q_program | qobject
                    else:
                        q_program = q_program | ~qobject

            #   Get the user-specific part of the query (e.g. ID, name, school)
            q_extra = self.query_from_criteria(recipient_type, data)

        qobject = (q_extra & q_program & Q(is_active=True))

        #strip out duplicate clauses
        #   Note: in some cases, the children of the Q object are unhashable.
        #   Keep these separate.
        clauses_hashable = []
        clauses_unhashable = []
        for clause in qobject.children:
            if isinstance(clause, Q) or (isinstance(clause, tuple)
                                         and isinstance(
                                             clause[1], collections.Hashable)):
                clauses_hashable.append(clause)
            else:
                clauses_unhashable.append(clause)
        qobject.children = list(set(clauses_hashable)) + clauses_unhashable

        if subquery:
            qobject = qobject & subquery
        return qobject