class StyleguideData(models.Model): """ Data we store for the styleguide Each user gets one of these and we use it to store data needed to test out the styleguide. """ user = models.OneToOneField(User) thumbnail = S3EnabledImageField(blank=True, upload_to='styleguide/thumbnail/', thumb_sizes=((169, 100), ))
class Video(models.Model): """Central object in the system""" video_id = models.CharField(max_length=255, unique=True) title = models.CharField(max_length=2048, blank=True) description = models.TextField(blank=True) duration = models.PositiveIntegerField(null=True, blank=True) allow_community_edits = models.BooleanField() allow_video_urls_edit = models.BooleanField(default=True) writelock_time = models.DateTimeField(null=True, editable=False) writelock_session_key = models.CharField(max_length=255, editable=False) writelock_owner = models.ForeignKey(User, null=True, editable=False, related_name="writelock_owners") is_subtitled = models.BooleanField(default=False) was_subtitled = models.BooleanField(default=False, db_index=True) thumbnail = models.CharField(max_length=500, blank=True) s3_thumbnail = S3EnabledImageField(blank=True, upload_to='video/thumbnail/') edited = models.DateTimeField(null=True, editable=False) created = models.DateTimeField(auto_now_add=True) user = models.ForeignKey(User, null=True, blank=True) followers = models.ManyToManyField(User, blank=True, related_name='followed_videos') complete_date = models.DateTimeField(null=True, blank=True, editable=False) subtitles_fetched_count = models.IntegerField(default=0, db_index=True) widget_views_count = models.IntegerField(default=0, db_index=True) view_count = models.PositiveIntegerField(default=0, db_index=True) subtitles_fetched_counter = RedisSimpleField('video_id', changed_video_set) widget_views_counter = RedisSimpleField('video_id', changed_video_set) view_counter = RedisSimpleField('video_id', changed_video_set) # Denormalizing the subtitles(had_version) count, in order to get faster joins # updated from update_languages_count() languages_count = models.PositiveIntegerField(default=0, db_index=True) def __unicode__(self): title = self.title_display() if len(title) > 70: title = title[:70] + '...' return title def title_display(self): if self.title: return self.title try: url = self.videourl_set.all()[:1].get().url if not url: return 'No title' except models.ObjectDoesNotExist: return 'No title' url = url.strip('/') if url.startswith('http://'): url = url[7:] parts = url.split('/') if len(parts) > 1: title = '%s/.../%s' % (parts[0], parts[-1]) else: title = url if title > 35: title = title[:35] + '...' return title def update_view_counter(self): self.view_counter.incr() video_view_counter.incr() def update_subtitles_fetched(self, lang=None): self.subtitles_fetched_counter.incr() #Video.objects.filter(pk=self.pk).update(subtitles_fetched_count=models.F('subtitles_fetched_count')+1) update_subtitles_fetch_counter(self, lang) if lang: lang.subtitles_fetched_counter.incr() #SubtitleLanguage.objects.filter(pk=sub_lang.pk).update(subtitles_fetched_count=models.F('subtitles_fetched_count')+1) def get_thumbnail(self): if self.s3_thumbnail: return self.s3_thumbnail.thumb_url(100, 100) if self.thumbnail: return self.thumbnail return '' def get_small_thumbnail(self): if self.s3_thumbnail: return self.s3_thumbnail.thumb_url(50, 50) return '' @models.permalink def video_link(self): return ('videos:history', [self.video_id]) def thumbnail_link(self): if not self.thumbnail: return '' if self.thumbnail.startswith('http://'): return self.thumbnail return settings.MEDIA_URL + self.thumbnail def is_html5(self): try: return self.videourl_set.filter(original=True)[:1].get().is_html5() except models.ObjectDoesNotExist: return False def search_page_url(self): return self.get_absolute_url() def title_for_url(self): return self.title.replace('/', '-').replace('#', '').replace('?', '') @models.permalink def get_absolute_url(self, locale=None): kwargs = {} if locale: kwargs['locale'] = locale title = self.title_for_url() if title: return ('videos:video_with_title', [self.video_id, title], kwargs) return ('videos:video', [self.video_id], kwargs) def get_video_url(self): try: return self.videourl_set.filter( primary=True).all()[:1].get().effective_url except models.ObjectDoesNotExist: pass @classmethod def get_or_create_for_url(cls, video_url=None, vt=None, user=None): vt = vt or video_type_registrar.video_type_for_url(video_url) if not vt: return None, False try: video_url_obj = VideoUrl.objects.get(url=vt.convert_to_video_url()) return video_url_obj.video, False except models.ObjectDoesNotExist: pass try: video_url_obj = VideoUrl.objects.get(type=vt.abbreviation, **vt.create_kwars()) if user: Action.create_video_handler(video_url_obj.video, user) return video_url_obj.video, False except models.ObjectDoesNotExist: obj = Video() obj = vt.set_values(obj) if obj.title: obj.slug = slugify(obj.title) obj.user = user obj.save() user and obj.followers.add(user) Action.create_video_handler(obj, user) SubtitleLanguage(video=obj, is_original=True, is_forked=True).save() #Save video url video_url_obj = VideoUrl() if vt.video_id: video_url_obj.videoid = vt.video_id video_url_obj.url = vt.convert_to_video_url() video_url_obj.type = vt.abbreviation video_url_obj.original = True video_url_obj.primary = True video_url_obj.added_by = user video_url_obj.video = obj video_url_obj.save() return obj, True @property def language(self): ol = self._original_subtitle_language() if ol and ol.language: return ol.language @property def filename(self): from django.utils.text import get_valid_filename return get_valid_filename(self.__unicode__()) def lang_filename(self, language): name = self.filename lang = language.language or u'original' return u'%s.%s' % (name, lang) @property def subtitle_state(self): """Subtitling state for this video """ return NO_SUBTITLES if self.latest_version() \ is None else SUBTITLES_FINISHED def _original_subtitle_language(self): if not hasattr(self, '_original_subtitle'): try: original = self.subtitlelanguage_set.filter( is_original=True)[:1].get() except models.ObjectDoesNotExist: original = None setattr(self, '_original_subtitle', original) return getattr(self, '_original_subtitle') def has_original_language(self): original_language = self._original_subtitle_language() if original_language: return original_language.language != '' def subtitle_language(self, language_code=None): try: if language_code is None: return self._original_subtitle_language() else: return self.subtitlelanguage_set.filter( language=language_code).order_by( '-subtitle_count')[:1].get() except models.ObjectDoesNotExist: return None def subtitle_languages(self, language_code): return self.subtitlelanguage_set.filter(language=language_code) def version(self, version_no=None, language=None): if language is None: language = self.subtitle_language() return None if language is None else language.version(version_no) def latest_version(self, language_code=None): language = self.subtitle_language(language_code) return None if language is None else language.latest_version() def subtitles(self, version_no=None, language_code=None): version = self.version(version_no, language_code) if version: return version.subtitles() else: return Subtitle.objects.none() def update_languages_count(self): self.languages_count = self.subtitlelanguage_set.filter( had_version=True).count() self.save() def latest_subtitles(self, language_code=None): version = self.latest_version(language_code) return [] if version is None else version.subtitles() def translation_language_codes(self): """All iso language codes with finished translations.""" return set([ sl.language for sl in self.subtitlelanguage_set.filter( is_complete=True).filter(is_original=False) ]) @property def writelock_owner_name(self): """The user who currently has a subtitling writelock on this video.""" if self.writelock_owner == None: return "anonymous" else: return self.writelock_owner.__unicode__() @property def is_writelocked(self): """Is this video writelocked for subtitling?""" if self.writelock_time == None: return False delta = datetime.now() - self.writelock_time seconds = delta.days * 24 * 60 * 60 + delta.seconds return seconds < WRITELOCK_EXPIRATION def can_writelock(self, request): """Can I place a writelock on this video for subtitling?""" return self.writelock_session_key == \ request.browser_id or \ not self.is_writelocked def writelock(self, request): """Writelock this video for subtitling.""" self._make_writelock(request.user, request.browser_id) def _make_writelock(self, user, key): if user.is_authenticated(): self.writelock_owner = user else: self.writelock_owner = None self.writelock_session_key = key self.writelock_time = datetime.now() def release_writelock(self): """Writelock this video for subtitling.""" self.writelock_owner = None self.writelock_session_key = '' self.writelock_time = None def notification_list(self, exclude=None): qs = self.followers.exclude(changes_notification=False).exclude( is_active=False) if exclude: if not isinstance(exclude, (list, tuple)): exclude = [exclude] qs = qs.exclude( pk__in=[u.pk for u in exclude if u and u.is_authenticated()]) return qs def notification_list_all(self, exclude=None): users = [] for language in self.subtitlelanguage_set.all(): for u in language.notification_list(exclude): if not u in users: users.append(u) for user in self.notification_list(exclude): if not user in users: users.append(user) return users def update_complete_state(self): language = self.subtitle_language() if not language.has_version: self.is_subtitled = False else: self.is_subtitled = True self.was_subtitled = True def subtitle_language_dict(self): langs = {} for sl in self.subtitlelanguage_set.all(): if not sl.language: continue if sl.language in langs: langs[sl.language].append(sl) else: langs[sl.language] = [sl] return langs
class CustomUser(BaseUser, secureid.SecureIDMixin): AUTOPLAY_ON_BROWSER = 1 AUTOPLAY_ON_LANGUAGES = 2 DONT_AUTOPLAY = 3 AUTOPLAY_CHOICES = ( (AUTOPLAY_ON_BROWSER, 'Autoplay subtitles based on browser preferred languages'), (AUTOPLAY_ON_LANGUAGES, 'Autoplay subtitles in languages I know'), (DONT_AUTOPLAY, 'Don\'t autoplay subtitles')) PLAYBACK_MODE_MAGIC = 1 PLAYBACK_MODE_STANDARD = 2 PLAYBACK_MODE_BEGINNER = 3 PLAYBACK_MODE_CHOICES = ((PLAYBACK_MODE_MAGIC, 'Magical auto-pause'), (PLAYBACK_MODE_STANDARD, 'No automatic pausing'), (PLAYBACK_MODE_BEGINNER, 'Play for 4 seconds, then pause')) homepage = models.URLField(blank=True) preferred_language = models.CharField(max_length=16, choices=ALL_LANGUAGES, blank=True) picture = S3EnabledImageField(blank=True, upload_to='pictures/', thumb_sizes=[(240, 240), (110, 110), (100, 100), (50, 50), (30, 30)]) valid_email = models.BooleanField(default=False) # if true, items that end on the user activity stream will also be # sent as email notify_by_email = models.BooleanField(default=True) # if true, items that end on the user activity stream will also be # sent as a message notify_by_message = models.BooleanField(default=True) allow_3rd_party_login = models.BooleanField(default=False) biography = models.TextField('Bio', blank=True) autoplay_preferences = models.IntegerField(choices=AUTOPLAY_CHOICES, default=AUTOPLAY_ON_BROWSER) award_points = models.IntegerField(default=0) last_ip = models.GenericIPAddressField(blank=True, null=True) # videos witch are related to user. this is for quicker queries videos = models.ManyToManyField('videos.Video', blank=True) # for some login backends we end up with a full name but not # a first name, last name pair. full_name = models.CharField(max_length=63, blank=True, default='') partner = models.ForeignKey('teams.Partner', blank=True, null=True) is_partner = models.BooleanField(default=False) pay_rate_code = models.CharField(max_length=3, blank=True, default='') can_send_messages = models.BooleanField(default=True) show_tutorial = models.BooleanField(default=True) # Whenever a user hides the "You have XX new messages" alert, we record # the id of the last message. We don't show the alert again until the # user has a message newer than that message. last_hidden_message_id = models.PositiveIntegerField(blank=True, default=0) playback_mode = models.IntegerField(choices=PLAYBACK_MODE_CHOICES, default=PLAYBACK_MODE_STANDARD) created_by = models.ForeignKey('self', null=True, blank=True, related_name='created_users') # For storing usernames of deactivated accounts, deleted accounts should not store the old username username_old = models.CharField(max_length=30, blank=True, null=True, default='') SECURE_ID_KEY = 'User' objects = CustomUserManager() cache = ModelCacheManager(default_cache_pattern='user') # Fields that constitute a user's profile, things like names, bios, etc. # When these change we emit the user_profile_changed signal. PROFILE_FIELDS = [ 'first_name', 'last_name', 'full_name', 'biography', 'picture', 'homepage', 'email', ] class Meta: db_table = 'auth_customuser' verbose_name = 'User' def __init__(self, *args, **kwargs): super(CustomUser, self).__init__(*args, **kwargs) self.start_tracking_profile_fields() def __unicode__(self): if self.is_amara_anonymous: return settings.ANONYMOUS_FULL_NAME elif not self.is_active: return ugettext('Retired user') elif self.first_name or self.last_name: return self.get_full_name() elif self.full_name: return self.full_name else: return self.username @staticmethod def generate_random_username(): username = str(uuid.uuid4())[0:30] try: CustomUser.objects.get(username=username) return generate_random_username() except CustomUser.DoesNotExist: return username @property def display_username(self): if self.is_active: return self.username else: return ugettext('Retired user') @property def username_with_fullname(self): if self.is_active: return self.username + ("" if unicode(self) == self.username else " ({})".format(unicode(self))) else: return ugettext('Retired user') # Returns a dictionary in the select2 data format def get_select2_format(self): return {'id': self.username, 'text': self.username_with_fullname} def sent_message(self): """ Should be called each time a user sends a message. This is used to control if a user is spamming. """ if hasattr(settings, 'MESSAGES_SENT_WINDOW_MINUTES') and \ hasattr(settings, 'MESSAGES_SENT_LIMIT'): SentMessageDate.objects.sent_message(self) self._check_sent_messages() def _check_sent_messages(self): if hasattr(settings, 'MESSAGES_SENT_WINDOW_MINUTES') and \ hasattr(settings, 'MESSAGES_SENT_LIMIT'): if SentMessageDate.objects.check_too_many_messages(self): self.de_activate() def de_activate(self): if not self.is_superuser: self.is_active = False self.save() import tasks tasks.notify_blocked_user.delay(self) def deactivate_account(self): with transaction.atomic(): self.unlink_external() self.team_members.all().delete() self.username_old = self.username self.username = CustomUser.generate_random_username() self.is_active = False self.save() signals.user_account_deactivated.send(sender=self) def delete_account_data(self): # Alternate implementation is to blank all the fields except for some fields # indicated in skip_fields # # for field in self._meta.fields: # if field.name in skip_fields: # continue # if field.default != NOT_PROVIDED: # setattr(self, field.name, field.default) # else: # setattr(self, field.name, None) self.username = CustomUser.generate_random_username() self.username_old = None self.first_name = "" self.last_name = "" self.picture = None self.email = "" self.homepage = "" self.biography = "" self.full_name = "" self.save() # Deletes videos this user has uploaded and no one else has added subtitles to # Also deletes uploaded videos without subtitles # Does not delete team videos def delete_self_subtitled_videos(self): for video in self.videos.all(): if (video.is_solo_subtitled_by_uploader() and not video.is_team_video()): video.delete() def has_fullname_set(self): return any([self.first_name, self.last_name, self.full_name]) def display_name(self): if self.has_fullname_set(): return u'{} ({})'.format(unicode(self), self.username) else: return unicode(self.username) def save(self, *args, **kwargs): send_confirmation = False if not self.email: self.valid_email = False elif self.pk: try: before_save = self.__class__._default_manager.get(pk=self.pk) send_confirmation = before_save.email != self.email except models.ObjectDoesNotExist: send_confirmation = True elif self.email: send_confirmation = True if send_confirmation: self.valid_email = False send_email_confirmation = kwargs.pop('send_email_confirmation', True) if self.pk: self.check_profile_changed() super(CustomUser, self).save(*args, **kwargs) self.start_tracking_profile_fields() if send_confirmation and send_email_confirmation: EmailConfirmation.objects.send_confirmation(self) def start_tracking_profile_fields(self): self._initial_profile_data = self.calc_profile_data() def calc_profile_data(self): return { name: getattr(self, name) for name in CustomUser.PROFILE_FIELDS } def check_profile_changed(self): if self.calc_profile_data() != self._initial_profile_data: signals.user_profile_changed.send(self) def clean(self): if '$' in self.username: raise ValidationError("usernames can't contain the '$' character") def set_last_hidden_message_id(self, request, message_id): if message_id != self.last_hidden_message_id: self.last_hidden_message_id = message_id self.save() # cycle the session key to bust the varnish cache request.session.cycle_key() def new_messages_count(self): """ Number of messages we should show in the "You have XX new messages alert" These are messages that: - Are unread - Have come in after the last time the user hide that message, or viewed their inbox """ from messages.models import Message qs = (Message.objects.for_user(self).filter( read=False, id__gt=self.last_hidden_message_id)) return qs.count() def last_message_id(self): """ The id of the last message for the user. Returns: message id, or 0 if there are no messages """ from messages.models import Message qs = Message.objects.for_user(self).order_by('-id')[:1] if qs: return qs[0].id else: return 0 def tutorial_was_shown(self): CustomUser.objects.filter(pk=self.id).update(show_tutorial=False) def set_playback_mode(self, playback_mode): CustomUser.objects.filter(pk=self.id).update( playback_mode=playback_mode) @classmethod def displayable_users(self, ids): return self.objects.filter(pk__in=ids).values_list( 'pk', 'first_name', 'last_name', 'username') @classmethod def video_followers_change_handler(cls, sender, instance, action, reverse, model, pk_set, **kwargs): from videos.models import SubtitleLanguage if reverse and action == 'post_add': #instance is User for video_pk in pk_set: cls.videos.through.objects.get_or_create( video__pk=video_pk, customuser=instance, defaults={'video_id': video_pk}) elif reverse and action == 'post_remove': #instance is User for video_pk in pk_set: if not SubtitleLanguage.objects.filter( followers=instance, video__pk=video_pk).exists(): instance.videos.remove(video_pk) elif not reverse and action == 'post_add': #instance is Video for user_pk in pk_set: cls.videos.through.objects.get_or_create( video=instance, customuser__pk=user_pk, defaults={'customuser_id': user_pk}) elif not reverse and action == 'post_remove': #instance is Video for user_pk in pk_set: if not SubtitleLanguage.objects.filter( followers__pk=user_pk, video=instance).exists(): instance.customuser_set.remove(user_pk) elif reverse and action == 'post_clear': #instance is User cls.videos.through.objects.filter(customuser=instance) \ .exclude(video__subtitlelanguage__followers=instance).delete() elif not reverse and action == 'post_clear': #instance is Video cls.videos.through.objects.filter(video=instance) \ .exclude(customuser__followed_languages__video=instance).delete() @classmethod def sl_followers_change_handler(cls, sender, instance, action, reverse, model, pk_set, **kwargs): from videos.models import Video, SubtitleLanguage if reverse and action == 'post_add': #instance is User for sl_pk in pk_set: sl = SubtitleLanguage.objects.get(pk=sl_pk) cls.videos.through.objects.get_or_create(video=sl.video, customuser=instance) elif reverse and action == 'post_remove': #instance is User for sl_pk in pk_set: if not Video.objects.filter( followers=instance, subtitlelanguage__pk=sl_pk).exists(): sl = SubtitleLanguage.objects.get(pk=sl_pk) instance.videos.remove(sl.video) elif not reverse and action == 'post_add': #instance is SubtitleLanguage for user_pk in pk_set: cls.videos.through.objects.get_or_create( video=instance.video, customuser__pk=user_pk, defaults={'customuser_id': user_pk}) elif not reverse and action == 'post_remove': #instance is SubtitleLanguage for user_pk in pk_set: if not Video.objects.filter( followers__pk=user_pk, subtitlelanguage=instance).exists(): instance.video.customuser_set.remove(user_pk) elif reverse and action == 'post_clear': #instance is User cls.videos.through.objects.filter(customuser=instance) \ .exclude(video__subtitlelanguage__followers=instance).delete() elif not reverse and action == 'post_clear': #instance is SubtitleLanguage cls.videos.through.objects.filter(video=instance) \ .exclude(customuser__followed_languages__video=instance.video).delete() def get_languages(self): """Get a list of language codes that the user speaks.""" return self.cache.get_or_calc("languages", self.calc_languages) def calc_languages(self): return list( self.userlanguage_set.order_by("priority").values_list('language', flat=True)) def set_languages(self, languages): with transaction.atomic(): # need to delete all the set languages since there is some funky stuff # happening if a user sets the same languages but with different priorities self.userlanguage_set.all().delete() self.userlanguage_set.set([ UserLanguage.objects.create(user=self, language=l["language"], priority=l["priority"]) for l in languages ]) self.cache.invalidate() signals.user_profile_changed.send(self) def get_language_names(self): """Get a list of language names that the user speaks.""" return [ translation.get_language_label(lc) for lc in self.get_languages() ] def get_language_codes_and_names(self): """Get a list of language codes/names that the user speaks.""" return [(lc, translation.get_language_label(lc)) for lc in self.get_languages()] def speaks_language(self, language_code): return language_code in [l.language for l in self.get_languages()] def is_team_manager(self): cached_value = self.cache.get('is-manager') if cached_value is not None: return cached_value is_manager = self.managed_teams().exists() self.cache.set('is-manager', is_manager) return is_manager def managed_teams(self, include_manager=True): from teams.models import TeamMember possible_roles = [TeamMember.ROLE_OWNER, TeamMember.ROLE_ADMIN] if include_manager: possible_roles.append(TeamMember.ROLE_MANAGER) return self.teams.filter(members__role__in=possible_roles) def messageable_teams(self): from teams.models import Team from teams.permissions import can_message_all_members teams = self.teams.all() messageable_team_ids = [ t.id for t in teams if can_message_all_members(t, self) ] partners = self.managed_partners.all() teams = [list(p.teams.all()) for p in partners] partner_teams_ids = [team.id for qs in teams for team in qs] messageable_team_ids = messageable_team_ids + partner_teams_ids return Team.objects.filter(id__in=messageable_team_ids) def open_tasks(self): from teams.models import Task return Task.objects.incomplete().filter(assignee=self) def _get_gravatar(self, size, default='mm'): url = "https://www.gravatar.com/avatar/" + hashlib.md5( self.email.lower().encode('utf-8')).hexdigest() + "?" url += urllib.urlencode({'d': default, 's': str(size)}) return url # old UI avatars def _get_avatar_by_size(self, size): if self.picture: return self.picture.thumb_url(size, size) else: return self._get_gravatar(size) def avatar(self): return self._get_avatar_by_size(100) def small_avatar(self): return self._get_avatar_by_size(50) def large_avatar(self): return self._get_avatar_by_size(240) # future UI avatar def _get_avatar(self, size): if self.picture: return self.picture.thumb_url(size, size) else: return self._get_gravatar( size, default=DEFAULT_AVATAR_URL.format(size=size)) def avatar_tag(self): avatar = self._get_avatar(30) return mark_safe( '<span class="avatar"><img src="{}"></span>'.format(avatar)) def avatar_tag_alert(self): avatar = self._get_avatar(30) return mark_safe( '<span class="avatar avatar-alert"><img src="{}"></span>'.format( avatar)) def avatar_tag_medium(self): avatar = self._get_avatar(50) return mark_safe( '<span class="avatar avatar-md"><img src="{}"></span>'.format( avatar)) def avatar_tag_large(self): avatar = self._get_avatar(100) return mark_safe( '<span class="avatar avatar-lg"><img src="{}"></span>'.format( avatar)) def avatar_tag_extra_large(self): avatar = self._get_avatar(110) return mark_safe( '<span class="avatar avatar-xl"><img src="{}"></span>'.format( avatar)) def get_absolute_url(self): return reverse('profiles:profile', args=(self.username, )) def send_message_url(self, absolute_url=False): url = '{}?user={}'.format(reverse('messages:new'), urlquote(self.username)) if absolute_url: url = "{}://{}{}".format(settings.DEFAULT_PROTOCOL, settings.HOSTNAME, url) return url @property def language(self): return self.get_preferred_language_display() def guess_best_lang(self, request=None): if self.preferred_language: return self.preferred_language user_languages = self.get_languages() if user_languages: return user_languages[0] if request: languages = translation.get_user_languages_from_request(request) if languages: return languages[0] return 'en' def guess_is_rtl(self, request=None): return translation.is_rtl(self.guess_best_lang(request)) @models.permalink def profile_url(self): return ('profiles:profile', [self.pk]) def hash_for_video(self, video_id): return hashlib.sha224(settings.SECRET_KEY + str(self.pk) + video_id).hexdigest() @classmethod def get_amara_anonymous(cls): return get_amara_anonymous_user() @property def is_amara_anonymous(self): return self.pk == settings.ANONYMOUS_USER_ID @property def is_external(self): """ Checks whether accout is external It can me an OpeenId link or a token stored as a ThirdPartyAccount """ try: l = self.openid_connect_link return True except: from thirdpartyaccounts import get_thirdpartyaccount_types for thirdpartyaccount_type in get_thirdpartyaccount_types(): m = apps.get_model(thirdpartyaccount_type[0], thirdpartyaccount_type[1]) if (m is not None) and (len(m.objects.for_user(self)) > 0): return True return False def has_valid_password(self): # remove this post-1.9 when setting is used validator = PasswordStrengthValidator() try: validator.validate(self.password) except ValidationError: return False return len(self.password) > 0 and self.has_usable_password() ''' Unlinks external authentication accounts (OAuth, Google, Facebook, etc. logins) ''' def unlink_external(self): from thirdpartyaccounts import get_thirdpartyaccount_types for thirdpartyaccount_type in get_thirdpartyaccount_types(): m = apps.get_model(thirdpartyaccount_type[0], thirdpartyaccount_type[1]) if m is not None: m.objects.for_user(self).delete() try: self.openid_connect_link.delete() except: pass def check_api_key(self, key): try: return self.api_key.key == key except AmaraApiKey.DoesNotExist: return False def get_api_key(self): return AmaraApiKey.objects.get_or_create(user=self)[0].key def ensure_api_key_created(self): AmaraApiKey.objects.get_or_create(user=self)
class Team(models.Model): APPLICATION = 1 INVITATION_BY_MANAGER = 2 INVITATION_BY_ALL = 3 OPEN = 4 MEMBERSHIP_POLICY_CHOICES = ( (APPLICATION, _(u'Application')), (INVITATION_BY_MANAGER, _(u'Invitation by manager')), (INVITATION_BY_ALL, _(u'Invitation by any member')), (OPEN, _(u'Open')), ) MEMBER_REMOVE = 1 MANAGER_REMOVE = 2 MEMBER_ADD = 3 VIDEO_POLICY_CHOICES = ( (MEMBER_REMOVE, _(u'Members can add and remove video') ), #any member can add/delete video (MANAGER_REMOVE, _(u'Managers can add and remove video') ), #only managers can add/remove video (MEMBER_ADD, _(u'Members can only add videos') ) #members can only add video ) name = models.CharField(_(u'name'), max_length=250, unique=True) slug = models.SlugField(_(u'slug'), unique=True) description = models.TextField( _(u'description'), blank=True, help_text=_('All urls will be converted to links.')) logo = S3EnabledImageField(verbose_name=_(u'logo'), blank=True, upload_to='teams/logo/') membership_policy = models.IntegerField(_(u'membership policy'), choices=MEMBERSHIP_POLICY_CHOICES, default=OPEN) video_policy = models.IntegerField(_(u'video policy'), choices=VIDEO_POLICY_CHOICES, default=MEMBER_REMOVE) is_visible = models.BooleanField(_(u'publicly Visible?'), default=True) videos = models.ManyToManyField(Video, through='TeamVideo', verbose_name=_('videos')) users = models.ManyToManyField(User, through='TeamMember', related_name='teams', verbose_name=_('users')) points = models.IntegerField(default=0, editable=False) applicants = models.ManyToManyField(User, through='Application', related_name='applicated_teams', verbose_name=_('applicants')) created = models.DateTimeField(auto_now_add=True) highlight = models.BooleanField(default=False) video = models.ForeignKey(Video, null=True, blank=True, related_name='intro_for_teams', verbose_name=_(u'Intro Video')) application_text = models.TextField(blank=True) page_content = models.TextField( _(u'Page content'), blank=True, help_text=_(u'You can use markdown. This will replace Description.')) is_moderated = models.BooleanField(default=False) header_html_text = models.TextField( blank=True, default='', help_text=_(u"HTML that appears at the top of the teams page.")) last_notification_time = models.DateTimeField( editable=False, default=datetime.datetime.now) objects = TeamManager() class Meta: ordering = ['-name'] verbose_name = _(u'Team') verbose_name_plural = _(u'Teams') def __unicode__(self): return self.name def render_message(self, msg): context = { 'team': self, 'msg': msg, 'author': msg.author, 'author_page': msg.author.get_absolute_url(), 'team_page': self.get_absolute_url() } return render_to_string('teams/_team_message.html', context) def is_open(self): return self.membership_policy == self.OPEN def is_by_application(self): return self.membership_policy == self.APPLICATION @classmethod def get(cls, slug, user=None, raise404=True): if user: qs = cls.objects.for_user(user) else: qs = cls.objects.filter(is_visible=True) try: return qs.get(slug=slug) except cls.DoesNotExist: try: return qs.get(pk=int(slug)) except (cls.DoesNotExist, ValueError): pass if raise404: raise Http404 def logo_thumbnail(self): if self.logo: return self.logo.thumb_url(100, 100) def small_logo_thumbnail(self): if self.logo: return self.logo.thumb_url(50, 50) @models.permalink def get_absolute_url(self): return ('teams:detail', [self.slug]) def get_site_url(self): return 'http://%s%s' % (Site.objects.get_current().domain, self.get_absolute_url()) @models.permalink def get_edit_url(self): return ('teams:edit', [self.slug]) def is_manager(self, user): if not user.is_authenticated(): return False return self.members.filter(user=user, is_manager=True).exists() def is_member(self, user): if not user.is_authenticated(): return False return self.members.filter(user=user).exists() def can_remove_video(self, user, team_video=None): if not user.is_authenticated(): return False if self.video_policy == self.MANAGER_REMOVE and self.is_manager(user): return True if self.video_policy == self.MEMBER_REMOVE and self.is_member(user): return True return False def can_edit_video(self, user, team_video=None): if not user.is_authenticated(): return False return self.can_add_video(user) def can_add_video(self, user): if not user.is_authenticated(): return False if self.video_policy == self.MEMBER_REMOVE and self.is_member(user): return True return self.is_manager(user) def can_invite(self, user): if self.membership_policy == self.INVITATION_BY_MANAGER: return self.is_manager(user) return self.is_member(user) def can_approve_application(self, user): return self.is_member(user) @property def member_count(self): if not hasattr(self, '_member_count'): setattr(self, '_member_count', self.users.count()) return self._member_count @property def videos_count(self): if not hasattr(self, '_videos_count'): setattr(self, '_videos_count', self.videos.count()) return self._videos_count @property def applications_count(self): if not hasattr(self, '_applications_count'): setattr(self, '_applications_count', self.applications.count()) return self._applications_count def _lang_pair(self, lp, suffix): return SQ(content="{0}_{1}_{2}".format(lp[0], lp[1], suffix)) def _sq_expression(self, sq_list): if len(sq_list) == 0: return None else: return reduce(lambda x, y: x | y, sq_list) def _filter(self, sqs, sq_list): from haystack.query import SQ sq_expression = self._sq_expression(sq_list) return None if (sq_expression is None) else sqs.filter(sq_expression) def _exclude(self, sqs, sq_list): if sqs is None: return None sq_expression = self._sq_expression(sq_list) return sqs if sq_expression is None else sqs.exclude(sq_expression) def _base_sqs(self): from haystack.query import SearchQuerySet return SearchQuerySet().models(TeamVideo).filter(team_id=self.id) def get_videos_for_languages_haystack(self, languages): from utils.multi_query_set import MultiQuerySet languages.extend( [l[:l.find('-')] for l in languages if l.find('-') > -1]) languages = list(set(languages)) pairs_m, pairs_0, langs = [], [], [] for l1 in languages: langs.append(SQ(content='S_{0}'.format(l1))) for l0 in languages: if l1 != l0: pairs_m.append(self._lang_pair((l1, l0), "M")) pairs_0.append(self._lang_pair((l1, l0), "0")) qs_list = [] qs_list.append(self._filter(self._base_sqs(), pairs_m)) qs_list.append( self._exclude(self._filter(self._base_sqs(), pairs_0), pairs_m)) qs_list.append( self._exclude( self._base_sqs().filter(original_language__in=languages), pairs_m + pairs_0).order_by('has_lingua_franca')) qs_list.append( self._exclude(self._filter(self._base_sqs(), langs), pairs_m + pairs_0).exclude(original_language__in=languages)) qs_list.append( self._exclude(self._base_sqs(), langs + pairs_m + pairs_0).exclude(original_language__in=languages)) mqs = MultiQuerySet(*[qs for qs in qs_list if qs is not None]) # this is way more efficient than making a count from all the # constituent querysets. mqs.set_count(TeamVideo.objects.filter(team=self).count()) return qs_list, mqs def get_videos_for_languages(self, languages, CUTTOFF_DUPLICATES_NUM_VIDEOS_ON_TEAMS): from utils.multi_query_set import TeamMultyQuerySet languages.extend( [l[:l.find('-')] for l in languages if l.find('-') > -1]) langs_pairs = [] for l1 in languages: for l0 in languages: if not l1 == l0: langs_pairs.append('%s_%s' % (l1, l0)) qs = TeamVideoLanguagePair.objects.filter(language_pair__in=langs_pairs, team=self) \ .select_related('team_video', 'team_video__video') lqs = TeamVideoLanguage.objects.filter(team=self).select_related( 'team_video', 'team_video__video') qs1 = qs.filter(percent_complete__gt=0, percent_complete__lt=100) qs2 = qs.filter(percent_complete=0) qs3 = lqs.filter(is_original=True, is_complete=False, language__in=languages).order_by("is_lingua_franca") qs4 = lqs.filter(is_original=False, forked=True, is_complete=False, language__in=languages) mqs = TeamMultyQuerySet(qs1, qs2, qs3, qs4) total_count = TeamVideo.objects.filter(team=self).count() additional = TeamVideoLanguagePair.objects.none() all_videos = TeamVideo.objects.filter( team=self).select_related('video') if total_count == 0: mqs = all_videos else: if total_count < CUTTOFF_DUPLICATES_NUM_VIDEOS_ON_TEAMS: additional = all_videos.exclude(pk__in=[x.id for x in mqs]) else: additional = all_videos mqs = TeamMultyQuerySet(qs1, qs2, qs3, qs4, additional) return { 'qs': qs, 'lqs': lqs, 'qs1': qs1, 'qs2': qs2, 'qs3': qs3, 'qs4': qs4, 'videos': mqs, 'videos_count': len(mqs), 'additional_count': additional.count(), 'additional': additional[:50], 'lqs': lqs, 'qs': qs, }
class TeamVideo(models.Model): team = models.ForeignKey(Team) video = models.ForeignKey(Video) title = models.CharField(max_length=2048, blank=True) description = models.TextField( blank=True, help_text= _(u'Use this space to explain why you or your team need to caption or subtitle this video. Adding a note makes volunteers more likely to help out!' )) thumbnail = S3EnabledImageField( upload_to='teams/video_thumbnails/', null=True, blank=True, help_text=_( u'We automatically grab thumbnails for certain sites, e.g. Youtube' )) all_languages = models.BooleanField( _('Need help with all languages'), default=False, help_text=_( 'If you check this, other languages will not be displayed.')) added_by = models.ForeignKey(User) created = models.DateTimeField(auto_now_add=True) completed_languages = models.ManyToManyField(SubtitleLanguage, blank=True) class Meta: unique_together = (('team', 'video'), ) def __unicode__(self): return self.title or self.video.__unicode__() def can_remove(self, user): return self.team.can_remove_video(user, self) def can_edit(self, user): return self.team.can_edit_video(user, self) def link_to_page(self): if self.all_languages: return self.video.get_absolute_url() return self.video.video_link() @models.permalink def get_absolute_url(self): return ('teams:team_video', [self.pk]) def get_thumbnail(self): if self.thumbnail: return self.thumbnail.thumb_url(100, 100) if self.video.thumbnail: th = self.video.get_thumbnail() if th: return th if self.team.logo: return self.team.logo_thumbnail() return '' def _original_language(self): if not hasattr(self, 'original_language_code'): sub_lang = self.video.subtitle_language() setattr(self, 'original_language_code', None if not sub_lang else sub_lang.language) return getattr(self, 'original_language_code') def _calculate_percent_complete(self, sl0, sl1): # maybe move this to Video model in future. if not sl0 or not sl0.is_dependable(): return -1 if not sl1: return 0 if sl1.language == self._original_language(): return -1 if sl1.is_dependent(): if sl1.percent_done == 0: return 0 elif sl0.is_dependent(): l_dep0 = sl0.real_standard_language() l_dep1 = sl1.real_standard_language() if l_dep0 and l_dep1 and l_dep0.id == l_dep1.id: return sl1.percent_done else: return -1 else: l_dep1 = sl1.real_standard_language() return sl1.percent_done if \ l_dep1 and l_dep1.id == sl0.id else -1 else: sl1_subtitle_count = 0 latest_version = sl1.latest_version() if latest_version: sl1_subtitle_count = latest_version.subtitle_set.count() return 0 if sl1_subtitle_count == 0 else -1 def _update_team_video_language_pair(self, lang0, sl0, lang1, sl1): percent_complete = self._calculate_percent_complete(sl0, sl1) if sl1 is not None: tvlps = TeamVideoLanguagePair.objects.filter( team_video=self, subtitle_language_0=sl0, subtitle_language_1=sl1) else: tvlps = TeamVideoLanguagePair.objects.filter( team_video=self, subtitle_language_0__language=lang0, language_1=lang1) tvlp = None if len(tvlps) == 0 else tvlps[0] if not tvlp and percent_complete != -1: tvlp = TeamVideoLanguagePair(team_video=self, team=self.team, video=self.video, language_0=lang0, subtitle_language_0=sl0, language_1=lang1, subtitle_language_1=sl1, language_pair='{0}_{1}'.format( lang0, lang1), percent_complete=percent_complete) tvlp.save() elif tvlp and percent_complete != -1: tvlp.percent_complete = percent_complete tvlp.save() elif tvlp and percent_complete == -1: tvlp.delete() def _make_lp(self, lang0, sl0, lang1, sl1): percent_complete = self._calculate_percent_complete(sl0, sl1) if percent_complete == -1: return None else: return "{0}_{1}_{2}".format(lang0, lang1, "M" if percent_complete > 0 else "0") def _update_tvlp_for_languages(self, lang0, lang1, langs): sl0_list = langs.get(lang0, []) sl1_list = langs.get(lang1, []) if len(sl1_list) == 0: sl1_list = [None] for sl0 in sl0_list: for sl1 in sl1_list: self._update_team_video_language_pair(lang0, sl0, lang1, sl1) def _add_lps_for_languages(self, lang0, lang1, langs, lps): sl0_list = langs.get(lang0, []) sl1_list = langs.get(lang1, []) if len(sl1_list) == 0: sl1_list = [None] for sl0 in sl0_list: for sl1 in sl1_list: lp = self._make_lp(lang0, sl0, lang1, sl1) if lp: lps.append(lp) def update_team_video_language_pairs(self, lang_code_list=None): TeamVideoLanguagePair.objects.filter(team_video=self).delete() if lang_code_list is None: lang_code_list = [item[0] for item in settings.ALL_LANGUAGES] langs = self.video.subtitle_language_dict() for lang0, sl0_list in langs.items(): for lang1 in lang_code_list: if lang0 == lang1: continue self._update_tvlp_for_languages(lang0, lang1, langs) def searchable_language_pairs(self): lps = [] lang_code_list = [item[0] for item in settings.ALL_LANGUAGES] langs = self.video.subtitle_language_dict() for lang0, sl0_list in langs.items(): for lang1 in lang_code_list: if lang0 == lang1: continue self._add_lps_for_languages(lang0, lang1, langs, lps) return lps def _add_searchable_language(self, language, sublang_dict, sls): complete_sublangs = [] if language in sublang_dict: complete_sublangs = [ sl for sl in sublang_dict[language] if not sl.is_dependent() and sl.is_complete ] if len(complete_sublangs) == 0: sls.append("S_{0}".format(language)) def searchable_languages(self): sls = [] langs = self.video.subtitle_language_dict() for lang in settings.ALL_LANGUAGES: self._add_searchable_language(lang[0], langs, sls) return sls
class Team(models.Model): APPLICATION = 1 INVITATION_BY_MANAGER = 2 INVITATION_BY_ALL = 3 OPEN = 4 MEMBERSHIP_POLICY_CHOICES = ( (APPLICATION, _(u'Application')), (INVITATION_BY_MANAGER, _(u'Invitation by manager')), (INVITATION_BY_ALL, _(u'Invitation by any member')), (OPEN, _(u'Open')), ) MEMBER_REMOVE = 1 MANAGER_REMOVE = 2 MEMBER_ADD = 3 VIDEO_POLICY_CHOICES = ( (MEMBER_REMOVE, _(u'Members can add and remove video') ), #any member can add/delete video (MANAGER_REMOVE, _(u'Managers can add and remove video') ), #only managers can add/remove video (MEMBER_ADD, _(u'Members can only add videos') ) #members can only add video ) name = models.CharField(_(u'name'), max_length=250, unique=True) slug = models.SlugField(_(u'slug'), unique=True) description = models.TextField( _(u'description'), blank=True, help_text=_('All urls will be converted to links.')) logo = S3EnabledImageField(verbose_name=_(u'logo'), blank=True, upload_to='teams/logo/') membership_policy = models.IntegerField(_(u'membership policy'), choices=MEMBERSHIP_POLICY_CHOICES, default=OPEN) video_policy = models.IntegerField(_(u'video policy'), choices=VIDEO_POLICY_CHOICES, default=MEMBER_REMOVE) is_visible = models.BooleanField(_(u'publicly Visible?'), default=True) videos = models.ManyToManyField(Video, through='TeamVideo', verbose_name=_('videos')) users = models.ManyToManyField(User, through='TeamMember', related_name='teams', verbose_name=_('users')) points = models.IntegerField(default=0, editable=False) applicants = models.ManyToManyField(User, through='Application', related_name='applicated_teams', verbose_name=_('applicants')) invited = models.ManyToManyField(User, through='Invite', verbose_name=_('invited')) created = models.DateTimeField(auto_now_add=True) highlight = models.BooleanField(default=False) video = models.ForeignKey(Video, null=True, blank=True, related_name='intro_for_teams', verbose_name=_(u'Intro Video')) application_text = models.TextField(blank=True) page_content = models.TextField( _(u'Page content'), blank=True, help_text=_(u'You can use murkdown. This will replace Description.')) is_moderated = models.BooleanField(default=False) header_html_text = models.TextField( blank=True, default='', help_text=_(u"HTML that appears at the top of the teams page.")) objects = TeamManager() class Meta: ordering = ['-name'] verbose_name = _(u'Team') verbose_name_plural = _(u'Teams') def __unicode__(self): return self.name def is_open(self): return self.membership_policy == self.OPEN def is_by_application(self): return self.membership_policy == self.APPLICATION @classmethod def get(cls, slug, user=None, raise404=True): if user: qs = cls.objects.for_user(user) else: qs = cls.objects.filter(is_visible=True) try: return qs.get(slug=slug) except cls.DoesNotExist: try: return qs.get(pk=int(slug)) except (cls.DoesNotExist, ValueError): pass if raise404: raise Http404 def logo_thumbnail(self): if self.logo: return self.logo.thumb_url(100, 100) def small_logo_thumbnail(self): if self.logo: return self.logo.thumb_url(50, 50) @models.permalink def get_absolute_url(self): return ('teams:detail', [self.slug]) def get_site_url(self): return 'http://%s%s' % (Site.objects.get_current().domain, self.get_absolute_url()) @models.permalink def get_edit_url(self): return ('teams:edit', [self.slug]) def is_manager(self, user): if not user.is_authenticated(): return False return self.members.filter(user=user, is_manager=True).exists() def is_member(self, user): if not user.is_authenticated(): return False return self.members.filter(user=user).exists() def can_remove_video(self, user, team_video=None): if not user.is_authenticated(): return False if self.video_policy == self.MANAGER_REMOVE and self.is_manager(user): return True if self.video_policy == self.MEMBER_REMOVE and self.is_member(user): return True return False def can_edit_video(self, user, team_video=None): if not user.is_authenticated(): return False return self.can_add_video(user) def can_add_video(self, user): if not user.is_authenticated(): return False if self.video_policy == self.MEMBER_REMOVE and self.is_member(user): return True return self.is_manager(user) def can_invite(self, user): if self.membership_policy == self.INVITATION_BY_MANAGER: return self.is_manager(user) return self.is_member(user) def can_approve_application(self, user): return self.is_member(user) @property def member_count(self): if not hasattr(self, '_member_count'): setattr(self, '_member_count', self.users.count()) return self._member_count @property def videos_count(self): if not hasattr(self, '_videos_count'): setattr(self, '_videos_count', self.videos.count()) return self._videos_count @property def applications_count(self): if not hasattr(self, '_applications_count'): setattr(self, '_applications_count', self.applications.count()) return self._applications_count
class CustomUser(BaseUser): AUTOPLAY_ON_BROWSER = 1 AUTOPLAY_ON_LANGUAGES = 2 DONT_AUTOPLAY = 3 AUTOPLAY_CHOICES = ( (AUTOPLAY_ON_BROWSER, 'Autoplay subtitles based on browser preferred languages'), (AUTOPLAY_ON_LANGUAGES, 'Autoplay subtitles in languages I know'), (DONT_AUTOPLAY, 'Don\'t autoplay subtitles') ) homepage = models.URLField(blank=True) preferred_language = models.CharField( max_length=16, choices=ALL_LANGUAGES, blank=True) picture = S3EnabledImageField(blank=True, upload_to='pictures/') valid_email = models.BooleanField(default=False) # if true, items that end on the user activity stream will also be # sent as email notify_by_email= models.BooleanField(default=True) # if true, items that end on the user activity stream will also be # sent as a message notify_by_message = models.BooleanField(default=True) biography = models.TextField('Bio', blank=True) autoplay_preferences = models.IntegerField( choices=AUTOPLAY_CHOICES, default=AUTOPLAY_ON_BROWSER) award_points = models.IntegerField(default=0) last_ip = models.IPAddressField(blank=True, null=True) # videos witch are related to user. this is for quicker queries videos = models.ManyToManyField('videos.Video', blank=True) # for some login backends we end up with a full name but not # a first name, last name pair. full_name = models.CharField(max_length=63, blank=True, default='') partner = models.ForeignKey('teams.Partner', blank=True, null=True) is_partner = models.BooleanField(default=False) pay_rate_code = models.CharField(max_length=3, blank=True, default='') can_send_messages = models.BooleanField(default=True) show_tutorial = models.BooleanField(default=True) created_by = models.ForeignKey('self', null=True, blank=True, related_name='created_users') objects = CustomUserManager() cache = ModelCacheManager(default_cache_pattern='user') class Meta: verbose_name = 'User' def __unicode__(self): if not self.is_active: return ugettext('Retired user') if self.first_name or self.last_name: return self.get_full_name() elif self.full_name: return self.full_name else: return self.username def has_fullname_set(self): return any([self.first_name, self.last_name, self.full_name]) def display_name(self): if self.has_fullname_set(): return u'{} ({})'.format(unicode(self), self.username) else: return unicode(self.username) def save(self, *args, **kwargs): send_confirmation = False if not self.email: self.valid_email = False elif self.pk: try: before_save = self.__class__._default_manager.get(pk=self.pk) send_confirmation = before_save.email != self.email except models.ObjectDoesNotExist: send_confirmation = True elif self.email: send_confirmation = True if send_confirmation: self.valid_email = False send_email_confirmation = kwargs.pop('send_email_confirmation', True) super(CustomUser, self).save(*args, **kwargs) if send_confirmation and send_email_confirmation: EmailConfirmation.objects.send_confirmation(self) def unread_messages(self, hidden_meassage_id=None): from messages.models import Message qs = Message.objects.for_user(self).filter(read=False) try: if hidden_meassage_id: qs = qs.filter(pk__gt=hidden_meassage_id) except (ValueError, TypeError): pass return qs def unread_messages_count(self, hidden_meassage_id=None): return self.unread_messages(hidden_meassage_id).count() @classmethod def tutorial_was_shown(self, id): self.objects.filter(pk=id).update(show_tutorial=False) @classmethod def displayable_users(self, ids): return self.objects.filter(pk__in=ids).values_list('pk', 'first_name', 'last_name', 'username') @classmethod def video_followers_change_handler(cls, sender, instance, action, reverse, model, pk_set, **kwargs): from videos.models import SubtitleLanguage if reverse and action == 'post_add': #instance is User for video_pk in pk_set: cls.videos.through.objects.get_or_create(video__pk=video_pk, customuser=instance, defaults={'video_id': video_pk}) elif reverse and action == 'post_remove': #instance is User for video_pk in pk_set: if not SubtitleLanguage.objects.filter(followers=instance, video__pk=video_pk).exists(): instance.videos.remove(video_pk) elif not reverse and action == 'post_add': #instance is Video for user_pk in pk_set: cls.videos.through.objects.get_or_create(video=instance, customuser__pk=user_pk, defaults={'customuser_id': user_pk}) elif not reverse and action == 'post_remove': #instance is Video for user_pk in pk_set: if not SubtitleLanguage.objects.filter(followers__pk=user_pk, video=instance).exists(): instance.customuser_set.remove(user_pk) elif reverse and action == 'post_clear': #instance is User cls.videos.through.objects.filter(customuser=instance) \ .exclude(video__subtitlelanguage__followers=instance).delete() elif not reverse and action == 'post_clear': #instance is Video cls.videos.through.objects.filter(video=instance) \ .exclude(customuser__followed_languages__video=instance).delete() @classmethod def sl_followers_change_handler(cls, sender, instance, action, reverse, model, pk_set, **kwargs): from videos.models import Video, SubtitleLanguage if reverse and action == 'post_add': #instance is User for sl_pk in pk_set: sl = SubtitleLanguage.objects.get(pk=sl_pk) cls.videos.through.objects.get_or_create(video=sl.video, customuser=instance) elif reverse and action == 'post_remove': #instance is User for sl_pk in pk_set: if not Video.objects.filter(followers=instance, subtitlelanguage__pk=sl_pk).exists(): sl = SubtitleLanguage.objects.get(pk=sl_pk) instance.videos.remove(sl.video) elif not reverse and action == 'post_add': #instance is SubtitleLanguage for user_pk in pk_set: cls.videos.through.objects.get_or_create(video=instance.video, customuser__pk=user_pk, defaults={'customuser_id': user_pk}) elif not reverse and action == 'post_remove': #instance is SubtitleLanguage for user_pk in pk_set: if not Video.objects.filter(followers__pk=user_pk, subtitlelanguage=instance).exists(): instance.video.customuser_set.remove(user_pk) elif reverse and action == 'post_clear': #instance is User cls.videos.through.objects.filter(customuser=instance) \ .exclude(video__subtitlelanguage__followers=instance).delete() elif not reverse and action == 'post_clear': #instance is SubtitleLanguage cls.videos.through.objects.filter(video=instance) \ .exclude(customuser__followed_languages__video=instance.video).delete() def get_languages(self): """Get a list of language codes that the user speaks.""" return self.cache.get_or_calc("languages", self.calc_languages) def calc_languages(self): return list(self.userlanguage_set.order_by("priority").values_list('language', flat=True)) def set_languages(self, languages): with transaction.commit_on_success(): self.userlanguage_set.all().delete() self.userlanguage_set = [ UserLanguage(language=l["language"], priority=l["priority"]) for l in languages ] self.cache.invalidate() def get_language_names(self): """Get a list of language names that the user speaks.""" return [translation.get_language_label(lc) for lc in self.get_languages()] def get_language_codes_and_names(self): """Get a list of language codes/names that the user speaks.""" return [(lc, translation.get_language_label(lc)) for lc in self.get_languages()] def speaks_language(self, language_code): return language_code in [l.language for l in self.get_languages()] def is_team_manager(self): cached_value = self.cache.get('is-manager') if cached_value is not None: return cached_value is_manager = self.managed_teams().exists() self.cache.set('is-manager', is_manager) return is_manager def managed_teams(self, include_manager=True): from teams.models import TeamMember possible_roles = [TeamMember.ROLE_OWNER, TeamMember.ROLE_ADMIN] if include_manager: possible_roles.append(TeamMember.ROLE_MANAGER) return self.teams.filter(members__role__in=possible_roles) def messageable_teams(self): from teams.models import Team from teams.permissions import can_message_all_members teams = self.teams.all() messageable_team_ids = [t.id for t in teams if can_message_all_members(t, self)] partners = self.managed_partners.all() teams = [list(p.teams.all()) for p in partners] partner_teams_ids = [team.id for qs in teams for team in qs] messageable_team_ids = messageable_team_ids + partner_teams_ids return Team.objects.filter(id__in=messageable_team_ids) def open_tasks(self): from teams.models import Task return Task.objects.incomplete().filter(assignee=self) def _get_gravatar(self, size): url = "http://www.gravatar.com/avatar/" + hashlib.md5(self.email.lower().encode('utf-8')).hexdigest() + "?" url += urllib.urlencode({'d': 'mm', 's':str(size)}) return url def _get_avatar_by_size(self, size): if self.picture: return self.picture.thumb_url(size, size) else: return self._get_gravatar(size) def avatar(self): return self._get_avatar_by_size(100) def small_avatar(self): return self._get_avatar_by_size(50) @models.permalink def get_absolute_url(self): return ('profiles:profile', [urlquote(self.username)]) def send_message_url(self): return '{}?user={}'.format(reverse('messages:new'), urlquote(self.username)) @property def language(self): return self.get_preferred_language_display() def guess_best_lang(self, request=None): if self.preferred_language: return self.preferred_language user_languages = list(self.userlanguage_set.all()) if user_languages: return user_languages[0].language if request: languages = translation.get_user_languages_from_request(request) if languages: return languages[0] return 'en' def guess_is_rtl(self, request=None): return translation.is_rtl(self.guess_best_lang(request)) @models.permalink def profile_url(self): return ('profiles:profile', [self.pk]) def hash_for_video(self, video_id): return hashlib.sha224(settings.SECRET_KEY+str(self.pk)+video_id).hexdigest() @classmethod def get_anonymous(cls): user, created = cls.objects.get_or_create( pk=settings.ANONYMOUS_USER_ID, defaults={'username': '******'}) return user @property def is_anonymous(self): return self.pk == settings.ANONYMOUS_USER_ID @property def is_external(self): """ Checks whether accout is external It can me an OpeenId link or a token stored as a ThirdPartyAccount """ try: l = self.openid_connect_link return True except: from thirdpartyaccounts import get_thirdpartyaccount_types for thirdpartyaccount_type in get_thirdpartyaccount_types(): m = get_model(thirdpartyaccount_type[0], thirdpartyaccount_type[1]) if (m is not None) and (len(m.objects.for_user(self)) > 0): return True return False def has_valid_password(self): return len(self.password) > 0 and self.has_usable_password() def unlink_external(self): from thirdpartyaccounts import get_thirdpartyaccount_types for thirdpartyaccount_type in get_thirdpartyaccount_types(): m = get_model(thirdpartyaccount_type[0], thirdpartyaccount_type[1]) if m is not None: m.objects.for_user(self).delete() from socialauth.models import AuthMeta, OpenidProfile AuthMeta.objects.filter(user=self).delete() OpenidProfile.objects.filter(user=self).delete() try: self.openid_connect_link.delete() except: pass def get_api_key(self): return ApiKey.objects.get_or_create(user=self)[0].key def ensure_api_key_created(self): ApiKey.objects.get_or_create(user=self)
class CustomUser(BaseUser): AUTOPLAY_ON_BROWSER = 1 AUTOPLAY_ON_LANGUAGES = 2 DONT_AUTOPLAY = 3 AUTOPLAY_CHOICES = ( (AUTOPLAY_ON_BROWSER, 'Autoplay subtitles based on browser preferred languages'), (AUTOPLAY_ON_LANGUAGES, 'Autoplay subtitles in languages I know'), (DONT_AUTOPLAY, 'Don\'t autoplay subtitles')) homepage = models.URLField(blank=True) preferred_language = models.CharField(max_length=16, choices=ALL_LANGUAGES, blank=True) picture = S3EnabledImageField(blank=True, upload_to='pictures/') valid_email = models.BooleanField(default=False) # if true, items that end on the user activity stream will also be # sent as email notify_by_email = models.BooleanField(default=True) # if true, items that end on the user activity stream will also be # sent as a message notify_by_message = models.BooleanField(default=True) biography = models.TextField('Bio', blank=True) autoplay_preferences = models.IntegerField(choices=AUTOPLAY_CHOICES, default=AUTOPLAY_ON_BROWSER) award_points = models.IntegerField(default=0) last_ip = models.IPAddressField(blank=True, null=True) # videos witch are related to user. this is for quicker queries videos = models.ManyToManyField('videos.Video', blank=True) # for some login backends we end up with a full name but not # a first name, last name pair. full_name = models.CharField(max_length=63, blank=True, default='') partner = models.ForeignKey('teams.Partner', blank=True, null=True) is_partner = models.BooleanField(default=False) pay_rate_code = models.CharField(max_length=3, blank=True, default='') can_send_messages = models.BooleanField(default=True) third_party_accounts = models.ManyToManyField( "accountlinker.ThirdPartyAccount", related_name='users', verbose_name=_('third party accounts')) objects = UserManager() class Meta: verbose_name = 'User' def __unicode__(self): if not self.is_active: return ugettext('Retired user') if self.first_name: if self.last_name: return self.get_full_name() else: return self.first_name if self.full_name: return self.full_name return self.username def save(self, *args, **kwargs): send_confirmation = False if not self.email: self.valid_email = False elif self.pk: try: before_save = self.__class__._default_manager.get(pk=self.pk) send_confirmation = before_save.email != self.email except models.ObjectDoesNotExist: send_confirmation = True elif self.email: send_confirmation = True if send_confirmation: self.valid_email = False send_email_confirmation = kwargs.pop('send_email_confirmation', True) super(CustomUser, self).save(*args, **kwargs) if send_confirmation and send_email_confirmation: EmailConfirmation.objects.send_confirmation(self) def unread_messages(self, hidden_meassage_id=None): from messages.models import Message qs = Message.objects.for_user(self).filter(read=False) try: if hidden_meassage_id: qs = qs.filter(pk__gt=hidden_meassage_id) except (ValueError, TypeError): pass return qs def unread_messages_count(self, hidden_meassage_id=None): if not hasattr(self, '_unread_messages_count'): self._unread_messages_count = self.unread_messages( hidden_meassage_id=hidden_meassage_id).count() return self._unread_messages_count @classmethod def video_followers_change_handler(cls, sender, instance, action, reverse, model, pk_set, **kwargs): from videos.models import SubtitleLanguage if reverse and action == 'post_add': #instance is User for video_pk in pk_set: cls.videos.through.objects.get_or_create( video__pk=video_pk, customuser=instance, defaults={'video_id': video_pk}) elif reverse and action == 'post_remove': #instance is User for video_pk in pk_set: if not SubtitleLanguage.objects.filter( followers=instance, video__pk=video_pk).exists(): instance.videos.remove(video_pk) elif not reverse and action == 'post_add': #instance is Video for user_pk in pk_set: cls.videos.through.objects.get_or_create( video=instance, customuser__pk=user_pk, defaults={'customuser_id': user_pk}) elif not reverse and action == 'post_remove': #instance is Video for user_pk in pk_set: if not SubtitleLanguage.objects.filter( followers__pk=user_pk, video=instance).exists(): instance.customuser_set.remove(user_pk) elif reverse and action == 'post_clear': #instance is User cls.videos.through.objects.filter(customuser=instance) \ .exclude(video__subtitlelanguage__followers=instance).delete() elif not reverse and action == 'post_clear': #instance is Video cls.videos.through.objects.filter(video=instance) \ .exclude(customuser__followed_languages__video=instance).delete() @classmethod def sl_followers_change_handler(cls, sender, instance, action, reverse, model, pk_set, **kwargs): from videos.models import Video, SubtitleLanguage if reverse and action == 'post_add': #instance is User for sl_pk in pk_set: sl = SubtitleLanguage.objects.get(pk=sl_pk) cls.videos.through.objects.get_or_create(video=sl.video, customuser=instance) elif reverse and action == 'post_remove': #instance is User for sl_pk in pk_set: if not Video.objects.filter( followers=instance, subtitlelanguage__pk=sl_pk).exists(): sl = SubtitleLanguage.objects.get(pk=sl_pk) instance.videos.remove(sl.video) elif not reverse and action == 'post_add': #instance is SubtitleLanguage for user_pk in pk_set: cls.videos.through.objects.get_or_create( video=instance.video, customuser__pk=user_pk, defaults={'customuser_id': user_pk}) elif not reverse and action == 'post_remove': #instance is SubtitleLanguage for user_pk in pk_set: if not Video.objects.filter( followers__pk=user_pk, subtitlelanguage=instance).exists(): instance.video.customuser_set.remove(user_pk) elif reverse and action == 'post_clear': #instance is User cls.videos.through.objects.filter(customuser=instance) \ .exclude(video__subtitlelanguage__followers=instance).delete() elif not reverse and action == 'post_clear': #instance is SubtitleLanguage cls.videos.through.objects.filter(video=instance) \ .exclude(customuser__followed_languages__video=instance.video).delete() def get_languages(self): """ Just to control this query """ languages = cache.get('user_languages_%s' % self.pk) if languages is None: languages = self.userlanguage_set.all() cache.set('user_languages_%s' % self.pk, languages, 60 * 24 * 7) return languages def speaks_language(self, language_code): return language_code in [l.language for l in self.get_languages()] def managed_teams(self): from apps.teams.models import TeamMember return self.teams.filter(members__role__in=[ TeamMember.ROLE_OWNER, TeamMember.ROLE_ADMIN, TeamMember.ROLE_MANAGER ]) def messageable_teams(self): from apps.teams.models import Team from apps.teams.permissions import can_message_all_members teams = self.teams.all() messageable_team_ids = [ t.id for t in teams if can_message_all_members(t, self) ] partners = self.managed_partners.all() teams = [list(p.teams.all()) for p in partners] partner_teams_ids = [team.id for qs in teams for team in qs] messageable_team_ids = messageable_team_ids + partner_teams_ids return Team.objects.filter(id__in=messageable_team_ids) def open_tasks(self): from apps.teams.models import Task return Task.objects.incomplete().filter(assignee=self) def _get_gravatar(self, size): url = "http://www.gravatar.com/avatar/" + hashlib.md5( self.email.lower().encode('utf-8')).hexdigest() + "?" url += urllib.urlencode({'d': 'mm', 's': str(size)}) return url def _get_avatar_by_size(self, size): if self.picture: return self.picture.thumb_url(size, size) else: return self._get_gravatar(size) def avatar(self): return self._get_avatar_by_size(100) def small_avatar(self): return self._get_avatar_by_size(50) @models.permalink def get_absolute_url(self): return ('profiles:profile', [urlquote(self.username)]) @property def language(self): return self.get_preferred_language_display() def guess_best_lang(self, request=None): if self.preferred_language: return self.preferred_language user_languages = list(self.userlanguage_set.all()) if user_languages: return user_languages[0].language from utils.translation import get_user_languages_from_request if request: languages = get_user_languages_from_request(request) if languages: return languages[0] return 'en' def guess_is_rtl(self, request=None): from utils.translation import is_rtl return is_rtl(self.guess_best_lang(request)) @models.permalink def profile_url(self): return ('profiles:profile', [self.pk]) def hash_for_video(self, video_id): return hashlib.sha224(settings.SECRET_KEY + str(self.pk) + video_id).hexdigest() @classmethod def get_anonymous(cls): try: return cls.objects.get(pk=settings.ANONYMOUS_USER_ID) except cls.DoesNotExist: return None @property def is_anonymous(self): return self.pk == settings.ANONYMOUS_USER_ID def get_api_key(self): return ApiKey.objects.get_or_create(user=self)[0].key
class CustomUser(BaseUser): AUTOPLAY_ON_BROWSER = 1 AUTOPLAY_ON_LANGUAGES = 2 DONT_AUTOPLAY = 3 AUTOPLAY_CHOICES = ( (AUTOPLAY_ON_BROWSER, 'Autoplay subtitles based on browser preferred languages'), (AUTOPLAY_ON_LANGUAGES, 'Autoplay subtitles in languages I know'), (DONT_AUTOPLAY, 'Don\'t autoplay subtitles')) homepage = models.URLField(verify_exists=False, blank=True) preferred_language = models.CharField(max_length=16, choices=ALL_LANGUAGES, blank=True) picture = S3EnabledImageField(blank=True, upload_to='pictures/') valid_email = models.BooleanField(default=False) changes_notification = models.BooleanField(default=True) follow_new_video = models.BooleanField(default=True) biography = models.TextField('Tell us about yourself', blank=True) autoplay_preferences = models.IntegerField(choices=AUTOPLAY_CHOICES, default=AUTOPLAY_ON_BROWSER) award_points = models.IntegerField(default=0) last_ip = models.IPAddressField(blank=True, null=True) #videos witch are related to user. this is for quicker queries videos = models.ManyToManyField('videos.Video', blank=True) objects = UserManager() class Meta: verbose_name = 'User' def __unicode__(self): if not self.is_active: return ugettext('Retired user') if self.first_name: if self.last_name: return self.get_full_name() else: return self.first_name return self.username def unread_messages(self): from messages.models import Message return Message.objects.for_user(self).filter(read=False) @classmethod def video_followers_change_handler(cls, sender, instance, action, reverse, model, pk_set, **kwargs): from videos.models import SubtitleLanguage if reverse and action == 'post_add': #instance is User for video_pk in pk_set: cls.videos.through.objects.get_or_create( video__pk=video_pk, customuser=instance, defaults={'video_id': video_pk}) elif reverse and action == 'post_remove': #instance is User for video_pk in pk_set: if not SubtitleLanguage.objects.filter( followers=instance, video__pk=video_pk).exists(): instance.videos.remove(video_pk) elif not reverse and action == 'post_add': #instance is Video for user_pk in pk_set: cls.videos.through.objects.get_or_create( video=instance, customuser__pk=user_pk, defaults={'customuser_id': user_pk}) elif not reverse and action == 'post_remove': #instance is Video for user_pk in pk_set: if not SubtitleLanguage.objects.filter( followers__pk=user_pk, video=instance).exists(): instance.customuser_set.remove(user_pk) elif reverse and action == 'post_clear': #instance is User cls.videos.through.objects.filter(customuser=instance) \ .exclude(video__subtitlelanguage__followers=instance).delete() elif not reverse and action == 'post_clear': #instance is Video cls.videos.through.objects.filter(video=instance) \ .exclude(customuser__followed_languages__video=instance).delete() @classmethod def sl_followers_change_handler(cls, sender, instance, action, reverse, model, pk_set, **kwargs): from videos.models import Video, SubtitleLanguage if reverse and action == 'post_add': #instance is User for sl_pk in pk_set: sl = SubtitleLanguage.objects.get(pk=sl_pk) cls.videos.through.objects.get_or_create(video=sl.video, customuser=instance) elif reverse and action == 'post_remove': #instance is User for sl_pk in pk_set: if not Video.objects.filter( followers=instance, subtitlelanguage__pk=sl_pk).exists(): sl = SubtitleLanguage.objects.get(pk=sl_pk) instance.videos.remove(sl.video) elif not reverse and action == 'post_add': #instance is SubtitleLanguage for user_pk in pk_set: cls.videos.through.objects.get_or_create( video=instance.video, customuser__pk=user_pk, defaults={'customuser_id': user_pk}) elif not reverse and action == 'post_remove': #instance is SubtitleLanguage for user_pk in pk_set: if not Video.objects.filter( followers__pk=user_pk, subtitlelanguage=instance).exists(): instance.video.customuser_set.remove(user_pk) elif reverse and action == 'post_clear': #instance is User cls.videos.through.objects.filter(customuser=instance) \ .exclude(video__subtitlelanguage__followers=instance).delete() elif not reverse and action == 'post_clear': #instance is SubtitleLanguage cls.videos.through.objects.filter(video=instance) \ .exclude(customuser__followed_languages__video=instance.video).delete() def get_languages(self): """ Just to control this query """ languages = cache.get('user_languages_%s' % self.pk) if languages is None: languages = self.userlanguage_set.all() cache.set('user_languages_%s' % self.pk, languages, 60 * 24 * 7) return languages def speaks_language(self, language_code): return language_code in [l.language for l in self.get_languages()] def managed_teams(self): return self.teams.filter(members__is_manager=True) def _get_gravatar(self, size): url = "http://www.gravatar.com/avatar/" + hashlib.md5( self.email.lower()).hexdigest() + "?" url += urllib.urlencode({'d': 'mm', 's': str(size)}) return url def _get_avatar_by_size(self, size): if self.picture: return self.picture.thumb_url(size, size) else: return self._get_gravatar(size) def avatar(self): return self._get_avatar_by_size(100) def small_avatar(self): return self._get_avatar_by_size(50) @models.permalink def get_absolute_url(self): return ('profiles:profile', [urlquote_plus(self.username)]) @property def language(self): return self.get_preferred_language_display() @models.permalink def profile_url(self): return ('profiles:profile', [self.pk]) def hash_for_video(self, video_id): return hashlib.sha224(settings.SECRET_KEY + str(self.pk) + video_id).hexdigest() @classmethod def get_youtube_anonymous(cls): return cls.objects.get(pk=10000)
class Team(models.Model): APPLICATION = 1 INVITATION_BY_MANAGER = 2 INVITATION_BY_ALL = 3 OPEN = 4 MEMBERSHIP_POLICY_CHOICES = ( (APPLICATION, _(u'Application')), (INVITATION_BY_MANAGER, _(u'Invitation by manager')), (INVITATION_BY_ALL, _(u'Invitation by any member')), (OPEN, _(u'Open')), ) MEMBER_REMOVE = 1 MANAGER_REMOVE = 2 MEMBER_ADD = 3 VIDEO_POLICY_CHOICES = ( (MEMBER_REMOVE, _(u'Members can add and remove video') ), #any member can add/delete video (MANAGER_REMOVE, _(u'Managers can add and remove video') ), #only managers can add/remove video (MEMBER_ADD, _(u'Members can only add videos') ) #members can only add video ) name = models.CharField(_(u'name'), max_length=250, unique=True) slug = models.SlugField(_(u'slug'), unique=True) description = models.TextField( _(u'description'), blank=True, help_text=_('All urls will be converted to links.')) logo = S3EnabledImageField(verbose_name=_(u'logo'), blank=True, upload_to='teams/logo/') membership_policy = models.IntegerField(_(u'membership policy'), choices=MEMBERSHIP_POLICY_CHOICES, default=OPEN) video_policy = models.IntegerField(_(u'video policy'), choices=VIDEO_POLICY_CHOICES, default=MEMBER_REMOVE) is_visible = models.BooleanField(_(u'publicly Visible?'), default=True) videos = models.ManyToManyField(Video, through='TeamVideo', verbose_name=_('videos')) users = models.ManyToManyField(User, through='TeamMember', related_name='teams', verbose_name=_('users')) points = models.IntegerField(default=0, editable=False) applicants = models.ManyToManyField(User, through='Application', related_name='applicated_teams', verbose_name=_('applicants')) invited = models.ManyToManyField(User, through='Invite', verbose_name=_('invited')) created = models.DateTimeField(auto_now_add=True) highlight = models.BooleanField(default=False) video = models.ForeignKey(Video, null=True, blank=True, related_name='intro_for_teams', verbose_name=_(u'Intro Video')) application_text = models.TextField(blank=True) page_content = models.TextField( _(u'Page content'), blank=True, help_text=_(u'You can use murkdown. This will replace Description.')) is_moderated = models.BooleanField(default=False) header_html_text = models.TextField( blank=True, default='', help_text=_(u"HTML that appears at the top of the teams page.")) objects = TeamManager() class Meta: ordering = ['-name'] verbose_name = _(u'Team') verbose_name_plural = _(u'Teams') def __unicode__(self): return self.name def is_open(self): return self.membership_policy == self.OPEN def is_by_application(self): return self.membership_policy == self.APPLICATION @classmethod def get(cls, slug, user=None, raise404=True): if user: qs = cls.objects.for_user(user) else: qs = cls.objects.filter(is_visible=True) try: return qs.get(slug=slug) except cls.DoesNotExist: try: return qs.get(pk=int(slug)) except (cls.DoesNotExist, ValueError): pass if raise404: raise Http404 def logo_thumbnail(self): if self.logo: return self.logo.thumb_url(100, 100) def small_logo_thumbnail(self): if self.logo: return self.logo.thumb_url(50, 50) @models.permalink def get_absolute_url(self): return ('teams:detail', [self.slug]) def get_site_url(self): return 'http://%s%s' % (Site.objects.get_current().domain, self.get_absolute_url()) @models.permalink def get_edit_url(self): return ('teams:edit', [self.slug]) def is_manager(self, user): if not user.is_authenticated(): return False return self.members.filter(user=user, is_manager=True).exists() def is_member(self, user): if not user.is_authenticated(): return False return self.members.filter(user=user).exists() def can_remove_video(self, user, team_video=None): if not user.is_authenticated(): return False if self.video_policy == self.MANAGER_REMOVE and self.is_manager(user): return True if self.video_policy == self.MEMBER_REMOVE and self.is_member(user): return True return False def can_edit_video(self, user, team_video=None): if not user.is_authenticated(): return False return self.can_add_video(user) def can_add_video(self, user): if not user.is_authenticated(): return False if self.video_policy == self.MEMBER_REMOVE and self.is_member(user): return True return self.is_manager(user) def can_invite(self, user): if self.membership_policy == self.INVITATION_BY_MANAGER: return self.is_manager(user) return self.is_member(user) def can_approve_application(self, user): return self.is_member(user) @property def member_count(self): if not hasattr(self, '_member_count'): setattr(self, '_member_count', self.users.count()) return self._member_count @property def videos_count(self): if not hasattr(self, '_videos_count'): setattr(self, '_videos_count', self.videos.count()) return self._videos_count @property def applications_count(self): if not hasattr(self, '_applications_count'): setattr(self, '_applications_count', self.applications.count()) return self._applications_count def get_videos_for_languages(self, languages, CUTTOFF_DUPLICATES_NUM_VIDEOS_ON_TEAMS): from utils.multy_query_set import TeamMultyQuerySet languages.extend( [l[:l.find('-')] for l in languages if l.find('-') > -1]) langs_pairs = [] for l1 in languages: for l0 in languages: if not l1 == l0: langs_pairs.append('%s_%s' % (l1, l0)) qs = TeamVideoLanguagePair.objects.filter(language_pair__in=langs_pairs, team=self) \ .select_related('team_video', 'team_video__video') lqs = TeamVideoLanguage.objects.filter(team=self).select_related( 'team_video', 'team_video__video') qs1 = qs.filter(percent_complete__gt=0, percent_complete__lt=100) qs2 = qs.filter(percent_complete=0) qs3 = lqs.filter(is_original=True, is_complete=False, language__in=languages) qs4 = lqs.filter(is_original=False, forked=True, is_complete=False, language__in=languages) mqs = TeamMultyQuerySet(qs1, qs2, qs3, qs4) total_count = TeamVideo.objects.filter(team=self).count() additional = TeamVideoLanguagePair.objects.none() all_videos = TeamVideo.objects.filter( team=self).select_related('video') if total_count == 0: mqs = all_videos else: if total_count < CUTTOFF_DUPLICATES_NUM_VIDEOS_ON_TEAMS: additional = all_videos.exclude(pk__in=[x.id for x in mqs]) else: additional = all_videos mqs = TeamMultyQuerySet(qs1, qs2, qs3, qs4, additional) return { 'qs': qs, 'lqs': lqs, 'qs1': qs1, 'qs2': qs2, 'qs3': qs3, 'qs4': qs4, 'videos': mqs, 'videos_count': len(mqs), 'additional_count': additional.count(), 'additional': additional[:50], 'lqs': lqs, 'qs': qs, }
class CustomUser(BaseUser): AUTOPLAY_ON_BROWSER = 1 AUTOPLAY_ON_LANGUAGES = 2 DONT_AUTOPLAY = 3 AUTOPLAY_CHOICES = ( (AUTOPLAY_ON_BROWSER, 'Autoplay subtitles based on browser preferred languages'), (AUTOPLAY_ON_LANGUAGES, 'Autoplay subtitles in languages I know'), (DONT_AUTOPLAY, 'Don\'t autoplay subtitles')) homepage = models.URLField(verify_exists=False, blank=True) preferred_language = models.CharField(max_length=16, choices=ALL_LANGUAGES, blank=True) picture = S3EnabledImageField(blank=True, upload_to='pictures/') valid_email = models.BooleanField(default=False) changes_notification = models.BooleanField(default=True) biography = models.TextField('Tell us about yourself', blank=True) autoplay_preferences = models.IntegerField(choices=AUTOPLAY_CHOICES, default=AUTOPLAY_ON_BROWSER) award_points = models.IntegerField(default=0) last_ip = models.IPAddressField(blank=True, null=True) objects = UserManager() class Meta: verbose_name = 'User' def __unicode__(self): if not self.is_active: return ugettext('Anonymous') if self.first_name: if self.last_name: return self.get_full_name() else: return self.first_name return self.username def get_languages(self): """ Just to control this query """ languages = cache.get('user_languages_%s' % self.pk) if languages is None: languages = self.userlanguage_set.all() cache.set('user_languages_%s' % self.pk, languages, 60 * 24 * 7) return languages def managed_teams(self): return self.teams.filter(members__is_manager=True) def avatar(self): return self.picture.thumb_url(100, 100) def small_avatar(self): return self.picture.thumb_url(50, 50) @models.permalink def get_absolute_url(self): return ('profiles:profile', [urlquote_plus(self.username)]) @property def language(self): return self.get_preferred_language_display() @models.permalink def profile_url(self): return ('profiles:profile', [self.pk]) def hash_for_video(self, video_id): return hashlib.sha224(settings.SECRET_KEY + str(self.pk) + video_id).hexdigest() @classmethod def get_youtube_anonymous(cls): return cls.objects.get(pk=10000)
class TeamVideo(models.Model): team = models.ForeignKey(Team) video = models.ForeignKey(Video) title = models.CharField(max_length=2048, blank=True) description = models.TextField( blank=True, help_text= _(u'Use this space to explain why you or your team need to caption or subtitle this video. Adding a note makes volunteers more likely to help out!' )) thumbnail = S3EnabledImageField( upload_to='teams/video_thumbnails/', null=True, blank=True, help_text=_( u'We automatically grab thumbnails for certain sites, e.g. Youtube' )) all_languages = models.BooleanField( _('Need help with all languages'), default=False, help_text=_( 'If you check this, other languages will not be displayed.')) added_by = models.ForeignKey(User) completed_languages = models.ManyToManyField(SubtitleLanguage, blank=True) class Meta: unique_together = (('team', 'video'), ) def __unicode__(self): return self.title or self.video.__unicode__() def save(self, *args, **kwargs): created = bool(not self.pk) super(TeamVideo, self).save(*args, **kwargs) #asynchronous call if created: update_one_team_video.delay(self.id) def can_remove(self, user): return self.team.can_remove_video(user, self) def can_edit(self, user): return self.team.can_edit_video(user, self) def link_to_page(self): if self.all_languages: return self.video.get_absolute_url() return self.video.video_link() @models.permalink def get_absolute_url(self): return ('teams:team_video', [self.pk]) def get_thumbnail(self): if self.thumbnail: return self.thumbnail.thumb_url(100, 100) if self.video.thumbnail: th = self.video.get_thumbnail() if th: return th if self.team.logo: return self.team.logo_thumbnail() return '' def _calculate_percent_complete(self, sl0, sl1): # maybe move this to Video model in future. if not sl0 or not sl0.is_dependable(): return -1 if not sl1: return 0 if sl1.is_dependent(): if sl1.percent_done == 0: return 0 elif sl0.is_dependent(): l_dep0 = sl0.real_standard_language() l_dep1 = sl1.real_standard_language() if l_dep0 and l_dep1 and l_dep0.id == l_dep1.id: return sl1.percent_done else: return -1 else: l_dep1 = sl1.real_standard_language() return sl1.percent_done if \ l_dep1 and l_dep1.id == sl0.id else -1 else: sl1_subtitle_count = 0 latest_version = sl1.latest_version() if latest_version: sl1_subtitle_count = latest_version.subtitle_set.count() return 0 if sl1_subtitle_count == 0 else -1 def _update_team_video_language_pair(self, lang0, sl0, lang1, sl1): percent_complete = self._calculate_percent_complete(sl0, sl1) if sl1 is not None: tvlps = TeamVideoLanguagePair.objects.filter( team_video=self, subtitle_language_0=sl0, subtitle_language_1=sl1) else: tvlps = TeamVideoLanguagePair.objects.filter( team_video=self, subtitle_language_0=lang0, language_1=lang1) tvlp = None if len(tvlps) == 0 else tvlps[0] if not tvlp and percent_complete != -1: tvlp = TeamVideoLanguagePair(team_video=self, team=self.team, video=self.video, language_0=lang0, subtitle_language_0=sl0, language_1=lang1, subtitle_language_1=sl1, language_pair='{0}_{1}'.format( lang0, lang1), percent_complete=percent_complete) tvlp.save() elif tvlp and percent_complete != -1: tvlp.percent_complete = percent_complete tvlp.save() elif tvlp and percent_complete == -1: tvlp.remove() def _update_tvlp_for_languages(self, lang0, lang1, langs): sl0_list = langs[lang0] sl1_list = langs[lang1] if len(sl1_list) == 0: sl1_list = [None] for sl0 in sl0_list: for sl1 in sl1_list: self._update_team_video_language_pair(lang0, sl0, lang1, sl1) def _subtitle_language_multivalue_dict(self): langs = {} for sl in self.video.subtitlelanguage_set.all(): if not sl.language: continue if sl.language in langs: langs[sl.language].append(sl) else: langs[sl.language] = [sl] return langs def update_team_video_language_pairs(self, lang_code_list=None): TeamVideoLanguagePair.objects.filter(team_video=self).delete() if lang_code_list is None: lang_code_list = [item[0] for item in settings.ALL_LANGUAGES] langs = self._subtitle_language_multivalue_dict() for lang0, sl0_list in langs.items(): for lang1 in lang_code_list: if lang0 == lang1: continue self._update_tvlp_for_languages(lang0, lang1, langs) def update_team_video_language_pairs_for_sl(self, sl): if not sl.language: return lang_code_list = [item[0] for item in settings.ALL_LANGUAGES] TeamVideoLanguagePair.objects.filter(team_video=self, subtitle_language_0=sl).delete() TeamVideoLanguagePair.objects.filter(team_video=self, subtitle_language_1=sl).delete() TeamVideoLanguagePair.objects.filter(team_video=self, subtitle_language_1__is_null=True, language_1=sl.language).delete() langs = self._subtitle_language_multivalue_dict() for lang in lang_code_list: sl1_list = langs[lang] if len(sl1_list) == 0: sl1_list = [None] for sl1 in sl1_list: self._update_team_video_language_pair( sl.language, sl, lang, sl1) for sl0 in self.video.subtitlelanguage_set.all(): self._update_team_video_language_pair(sl0.language, sl0, sl.language, sl)