class GroupIndex(TagObjectSearchIndex, indexes.Indexable): text = TemplateResolveCharField(document=True, use_template=True) rendered = TemplateResolveCharField(use_template=True, indexed=False) name = indexes.CharField(model_attr='name') slug = indexes.CharField(model_attr='slug', indexed=False) public = indexes.BooleanField(model_attr='public') admins = indexes.MultiValueField(model_attr='admins', indexed=False) members = indexes.MultiValueField(model_attr='members', indexed=False) pendings = indexes.MultiValueField(model_attr='pendings', indexed=False) def get_model(self): return CosinnusGroup def index_queryset(self, using=None): return self.get_model().objects.select_related('media_tag').all()
class CosinnusConferenceIndex(CosinnusGroupIndexMixin, TagObjectSearchIndex, indexes.Indexable): text = TemplateResolveNgramField( document=True, use_template=True, template_name='search/indexes/cosinnus/cosinnusgroup_{field_name}.txt') rendered = TemplateResolveCharField( use_template=True, indexed=False, template_name='search/indexes/cosinnus/cosinnusgroup_{field_name}.txt') from_date = indexes.DateTimeField(model_attr='from_date', null=True) to_date = indexes.DateTimeField(model_attr='to_date', null=True) humanized_event_time_html = indexes.CharField(stored=True, indexed=False) participants_limit_count = indexes.IntegerField(stored=True, indexed=False) def get_model(self): return CosinnusConference def prepare_participant_count(self, obj): """ Mirrored the member count for simplicity """ return self.prepare_member_count(obj) def prepare_participants_limit_count(self, obj): """ Mirrored the member count for simplicity """ participation_managements = obj.participation_management.all() if len(participation_managements) > 0: return participation_managements[0].participants_limit return 0 def prepare_humanized_event_time_html(self, obj): return obj.get_humanized_event_time_html() def boost_model(self, obj, indexed_data): """ We boost a combined measure of 2 added factors: soonishnes (50%) and participant count (50%). This means that a soon happening event with lots of participants will rank highest and an far off event with no participants lowest. But it also means that soon happening events with no participants will still rank quite high, as will far off events with lots of participants. Factors: - The conference's date, highest being now() and lowest >= 12 months from now """ if obj.from_date: future_date_timedelta = obj.from_date - now() if future_date_timedelta.days < 0: if obj.to_date and (obj.to_date - now()).days > 0: rank_from_date = 0.1 # running events rank not nothing else: rank_from_date = 0.0 # past events rank worst else: rank_from_date = max( 1.0 - (future_date_timedelta.days / 365.0), 0) else: rank_from_date = 0.0 return rank_from_date
class CosinnusSocietyIndex(CosinnusGroupIndexMixin, TagObjectSearchIndex, indexes.Indexable): text = TemplateResolveNgramField( document=True, use_template=True, template_name='search/indexes/cosinnus/cosinnusgroup_{field_name}.txt') rendered = TemplateResolveCharField( use_template=True, indexed=False, template_name='search/indexes/cosinnus/cosinnusgroup_{field_name}.txt') def get_model(self): return CosinnusSociety def prepare_participant_count(self, obj): """ child projects for groups """ return obj.groups.count()
class CosinnusProjectIndex(CosinnusGroupIndexMixin, TagObjectSearchIndex, indexes.Indexable): text = TemplateResolveNgramField( document=True, use_template=True, template_name='search/indexes/cosinnus/cosinnusgroup_{field_name}.txt') rendered = TemplateResolveCharField( use_template=True, indexed=False, template_name='search/indexes/cosinnus/cosinnusgroup_{field_name}.txt') def get_model(self): return CosinnusProject def prepare_group_slug(self, obj): """ For projects assigned to a parent group, we link that group """ return obj.parent and obj.parent.slug or None def prepare_group_name(self, obj): """ Stub, overridden by individual indexes """ return obj.parent and obj.parent.name or None
class UserProfileIndex(LocalCachedIndexMixin, DocumentBoostMixin, StoredDataIndexMixin, TagObjectSearchIndex, indexes.Indexable): text = TemplateResolveNgramField( document=True, use_template=True, template_name='search/indexes/cosinnus/userprofile_{field_name}.txt') rendered = TemplateResolveCharField( use_template=True, indexed=False, template_name='search/indexes/cosinnus/userprofile_{field_name}.txt') boosted = indexes.CharField(model_attr='get_full_name', boost=BOOSTED_FIELD_BOOST) user_visibility_mode = indexes.BooleanField( default=True) # switch to filter differently on mt_visibility membership_groups = indexes.MultiValueField( model_attr='cosinnus_groups_pks' ) # ids of all groups the user is member/admin of admin_groups = indexes.MultiValueField( ) # ids of all groups the user is member/admin of portals = indexes.MultiValueField() location = indexes.LocationField(null=True) user_id = indexes.IntegerField(model_attr='user__id') created = indexes.DateTimeField(model_attr='user__date_joined') local_cached_attrs = ['_memberships_count'] def prepare_portals(self, obj): return list( obj.user.cosinnus_portal_memberships.values_list('group_id', flat=True)) def prepare_location(self, obj): if obj.media_tag and obj.media_tag.location_lat and obj.media_tag.location_lon: # this expects (lat,lon)! return "%s,%s" % (obj.media_tag.location_lat, obj.media_tag.location_lon) return None def prepare_title(self, obj): return obj.user.get_full_name() def prepare_slug(self, obj): return obj.user.username def get_image_field_for_icon(self, obj): return obj.get_image_field_for_icon() def prepare_url(self, obj): """ NOTE: UserProfiles always contain a relative URL! """ return reverse('cosinnus:profile-detail', kwargs={'username': obj.user.username}) def prepare_member_count(self, obj): """ Memberships for users """ return self._get_memberships_count(obj) def prepare_admin_groups(self, obj): return list( get_cosinnus_group_model().objects.get_for_user_group_admin_pks( obj.user)) def get_model(self): return get_user_profile_model() def index_queryset(self, using=None): qs = self.get_model().objects.all() qs = filter_active_users(qs, filter_on_user_profile_model=True) qs = qs.select_related('user').all() return qs def _get_memberships_count(self, obj): if not hasattr(obj, '_memberships_count'): setattr(obj, '_memberships_count', obj.user.cosinnus_memberships.count()) return obj._memberships_count def boost_model(self, obj, indexed_data): """ We boost by number of groups the user is a member of, normalized over the mean/stddev of the count of groups each portal user is a members of, in a range of [0.0..1.0] """ def qs_func(): return filter_portal_users( filter_active_users(get_user_model().objects.all())) mean, stddev = self.get_mean_and_stddev(qs_func, 'cosinnus_memberships') user_memberships_count = self._get_memberships_count(obj) memberships_rank = normalize_within_stddev(user_memberships_count, mean, stddev, stddev_factor=2.0) return memberships_rank def apply_boost_penalty(self, obj, indexed_data): """ Penaliize by 15% for not having an avatar image. @return: 1.0 for no penalty, a float in range [0.0..1.0] for a penalty """ if not self.get_image_field_for_icon(obj): return DEFAULT_BOOST_PENALTY_FOR_MISSING_IMAGE return 1.0